Load libraries

library(readxl) # for reading in excel files
library(janitor) # data checks and cleaning
library(glue) # for easy pasting
library(FactoMineR) # for PCA
library(factoextra) # for PCA
library(rstatix) # for stats
library(pheatmap) # for heatmaps
library(plotly) # for interactive plots
library(htmlwidgets) # for saving interactive plots
library(devtools)
library(notame) # used for feature clustering
library(doParallel)
library(igraph) # feature clustering
library(ggpubr) # visualizations
library(knitr) # clean table printing
library(mixOmics) # for multilevel PCAs
library(ggthemes)
library(pathview) # for functional analysis and KEGG annotation
library(ggcorrplot)
library(corrr)
library(ggthemes)
library(PCAtools)
library(tidyverse) # for everything

Read in data

# raw filtered metabolomics data in c18 (+)
omicsdata <- read_csv("Feature lists/c18Pos-Filtered-Data-05Jun23_946features.csv")

# metadata
metadata <- read_excel("Metadata-urine-c18pos.xlsx")

Wrangle data

metadata <- metadata %>%
  rename("sample_ID" = Sample_ID)
# rename "row ID"
omicsdata <- omicsdata %>%
  rename("row_ID" = `row ID`)

# how many features
nrow(omicsdata)
## [1] 946
# are there any duplicates?
omicsdata %>% get_dupes(mz_rt)
## # A tibble: 2 × 60
##   mz_rt         dupe_count row_ID `6101_U4_C18POS_14` `6110_U2_C18POS_34`
##   <chr>              <int>  <dbl>               <dbl>               <dbl>
## 1 369.152_4.502          2   4830              40321.               3464.
## 2 369.152_4.502          2   4832              40321.               3464.
## # ℹ 55 more variables: `6104_U2_C18POS_19` <dbl>, `6109_U4_C18POS_22` <dbl>,
## #   `6111_U1_C18POS_51` <dbl>, `6110_U3_C18POS_45` <dbl>,
## #   `6105_U1_C18POS_43` <dbl>, `6111_U4_C18POS_42` <dbl>,
## #   `6113_U2_C18POS_31` <dbl>, `6105_U2_C18POS_40` <dbl>,
## #   `6109_U1_C18POS_58` <dbl>, `6113_U4_C18POS_62` <dbl>,
## #   `6102_U1_C18POS_26_1` <dbl>, `6102_U2_C18POS_16` <dbl>,
## #   `6105_U4_C18POS_47` <dbl>, `6105_U3_C18POS_39` <dbl>, …

Remove duplicates

# remove dupes
omicsdata <- omicsdata %>% 
  distinct(mz_rt, .keep_all = TRUE)

# check again for dupes
omicsdata %>% get_dupes(mz_rt)
## # A tibble: 0 × 60
## # ℹ 60 variables: mz_rt <chr>, dupe_count <int>, row_ID <dbl>,
## #   6101_U4_C18POS_14 <dbl>, 6110_U2_C18POS_34 <dbl>, 6104_U2_C18POS_19 <dbl>,
## #   6109_U4_C18POS_22 <dbl>, 6111_U1_C18POS_51 <dbl>, 6110_U3_C18POS_45 <dbl>,
## #   6105_U1_C18POS_43 <dbl>, 6111_U4_C18POS_42 <dbl>, 6113_U2_C18POS_31 <dbl>,
## #   6105_U2_C18POS_40 <dbl>, 6109_U1_C18POS_58 <dbl>, 6113_U4_C18POS_62 <dbl>,
## #   6102_U1_C18POS_26_1 <dbl>, 6102_U2_C18POS_16 <dbl>,
## #   6105_U4_C18POS_47 <dbl>, 6105_U3_C18POS_39 <dbl>, …
# how many features
nrow(omicsdata)
## [1] 945

Remove weird empty column

colnames(omicsdata)
##  [1] "mz_rt"                                        
##  [2] "row_ID"                                       
##  [3] "6101_U4_C18POS_14"                            
##  [4] "6110_U2_C18POS_34"                            
##  [5] "6104_U2_C18POS_19"                            
##  [6] "6109_U4_C18POS_22"                            
##  [7] "6111_U1_C18POS_51"                            
##  [8] "6110_U3_C18POS_45"                            
##  [9] "6105_U1_C18POS_43"                            
## [10] "6111_U4_C18POS_42"                            
## [11] "6113_U2_C18POS_31"                            
## [12] "6105_U2_C18POS_40"                            
## [13] "6109_U1_C18POS_58"                            
## [14] "6113_U4_C18POS_62"                            
## [15] "6102_U1_C18POS_26_1"                          
## [16] "6102_U2_C18POS_16"                            
## [17] "6105_U4_C18POS_47"                            
## [18] "6105_U3_C18POS_39"                            
## [19] "6111_U2_C18POS_35"                            
## [20] "6103_U4_C18POS_53"                            
## [21] "6102_U3_C18POS_48"                            
## [22] "6102_U4_C18POS_50"                            
## [23] "6104_U4_C18POS_12"                            
## [24] "6101_U1_C18POS_59"                            
## [25] "6103_U3_C18POS_61"                            
## [26] "6108_U2_C18POS_27_1"                          
## [27] "6103_U2_C18POS_60"                            
## [28] "6101_U2_C18POS_30"                            
## [29] "6112_U2_C18POS_37"                            
## [30] "6113_U1_C18POS_24"                            
## [31] "6108_U4_C18POS_18"                            
## [32] "6104_U1_C18POS_55"                            
## [33] "6113_U3_C18POS_15"                            
## [34] "6101_U3_C18POS_29_1"                          
## [35] "6106_U3_C18POS_20"                            
## [36] "6106_U2_C18POS_46"                            
## [37] "6108_U1_C18POS_44"                            
## [38] "6111_U3_C18POS_54"                            
## [39] "6112_U4_C18POS_63"                            
## [40] "6109_U3_C18POS_52"                            
## [41] "6110_U1_C18POS_11"                            
## [42] "6110_U4_C18POS_start-10"                      
## [43] "6112_U3_C18POS_56"                            
## [44] "6108_U3_C18POS_28_1"                          
## [45] "6103_U1_C18POS_21"                            
## [46] "6106_U1_C18POS_23"                            
## [47] "6109_U2_C18POS_13"                            
## [48] "6106_U4_C18POS_36"                            
## [49] "6112_U1_C18POS_38"                            
## [50] "PooledQC6_C18POS_17"                          
## [51] "PooledQC11_C18POS_57"                         
## [52] "PooledQC9_C18POS_41"                          
## [53] "6104_U3_C18POS_32"                            
## [54] "PooledQC10_C18POS_49"                         
## [55] "PooledQC12_C18POS_64"                         
## [56] "PrerunPooledQC5tryagain-addednew3_C18POS_14_1"
## [57] "PooledQC8_C18POS_33"                          
## [58] "PooledQC7_C18POS_25"                          
## [59] "...59"
# remove weird lgl column
omicsdata <- omicsdata %>%
 dplyr::select(!where(is.logical))

colnames(omicsdata)
##  [1] "mz_rt"                                        
##  [2] "row_ID"                                       
##  [3] "6101_U4_C18POS_14"                            
##  [4] "6110_U2_C18POS_34"                            
##  [5] "6104_U2_C18POS_19"                            
##  [6] "6109_U4_C18POS_22"                            
##  [7] "6111_U1_C18POS_51"                            
##  [8] "6110_U3_C18POS_45"                            
##  [9] "6105_U1_C18POS_43"                            
## [10] "6111_U4_C18POS_42"                            
## [11] "6113_U2_C18POS_31"                            
## [12] "6105_U2_C18POS_40"                            
## [13] "6109_U1_C18POS_58"                            
## [14] "6113_U4_C18POS_62"                            
## [15] "6102_U1_C18POS_26_1"                          
## [16] "6102_U2_C18POS_16"                            
## [17] "6105_U4_C18POS_47"                            
## [18] "6105_U3_C18POS_39"                            
## [19] "6111_U2_C18POS_35"                            
## [20] "6103_U4_C18POS_53"                            
## [21] "6102_U3_C18POS_48"                            
## [22] "6102_U4_C18POS_50"                            
## [23] "6104_U4_C18POS_12"                            
## [24] "6101_U1_C18POS_59"                            
## [25] "6103_U3_C18POS_61"                            
## [26] "6108_U2_C18POS_27_1"                          
## [27] "6103_U2_C18POS_60"                            
## [28] "6101_U2_C18POS_30"                            
## [29] "6112_U2_C18POS_37"                            
## [30] "6113_U1_C18POS_24"                            
## [31] "6108_U4_C18POS_18"                            
## [32] "6104_U1_C18POS_55"                            
## [33] "6113_U3_C18POS_15"                            
## [34] "6101_U3_C18POS_29_1"                          
## [35] "6106_U3_C18POS_20"                            
## [36] "6106_U2_C18POS_46"                            
## [37] "6108_U1_C18POS_44"                            
## [38] "6111_U3_C18POS_54"                            
## [39] "6112_U4_C18POS_63"                            
## [40] "6109_U3_C18POS_52"                            
## [41] "6110_U1_C18POS_11"                            
## [42] "6110_U4_C18POS_start-10"                      
## [43] "6112_U3_C18POS_56"                            
## [44] "6108_U3_C18POS_28_1"                          
## [45] "6103_U1_C18POS_21"                            
## [46] "6106_U1_C18POS_23"                            
## [47] "6109_U2_C18POS_13"                            
## [48] "6106_U4_C18POS_36"                            
## [49] "6112_U1_C18POS_38"                            
## [50] "PooledQC6_C18POS_17"                          
## [51] "PooledQC11_C18POS_57"                         
## [52] "PooledQC9_C18POS_41"                          
## [53] "6104_U3_C18POS_32"                            
## [54] "PooledQC10_C18POS_49"                         
## [55] "PooledQC12_C18POS_64"                         
## [56] "PrerunPooledQC5tryagain-addednew3_C18POS_14_1"
## [57] "PooledQC8_C18POS_33"                          
## [58] "PooledQC7_C18POS_25"
# create long df for omics df
omicsdata_tidy <- omicsdata %>%
  pivot_longer(cols = 3:ncol(.),
               names_to = "sample_ID",
               values_to = "peak_height")

# combine meta and omics dfs
df_combined <- full_join(omicsdata_tidy,
                         metadata,
                         by = c("sample_ID" = "sample_ID"))

# separate mz and rt
df_combined_sep <- df_combined %>%
  separate(col = mz_rt,
           into = c("mz", "rt"),
           sep = "_") 

# convert columns to correct type
df_combined_sep$mz <- as.numeric(df_combined_sep$mz)
df_combined_sep$rt <- as.numeric(df_combined_sep$rt)
df_combined_sep$Subject <- as.character(df_combined_sep$Subject)
df_combined_sep$Intervention <- as.character(df_combined_sep$Intervention)

# rearrange column order
df_combined_sep <- df_combined_sep %>%
 dplyr::select(sample_ID, pre_post, Intervention, everything())

str(df_combined_sep)
## tibble [52,920 × 14] (S3: tbl_df/tbl/data.frame)
##  $ sample_ID        : chr [1:52920] "6101_U4_C18POS_14" "6110_U2_C18POS_34" "6104_U2_C18POS_19" "6109_U4_C18POS_22" ...
##  $ pre_post         : chr [1:52920] "post" "post" "post" "post" ...
##  $ Intervention     : chr [1:52920] "Yellow" "Yellow" "Yellow" "Red" ...
##  $ mz               : num [1:52920] 227 227 227 227 227 ...
##  $ rt               : num [1:52920] 0.553 0.553 0.553 0.553 0.553 0.553 0.553 0.553 0.553 0.553 ...
##  $ row_ID           : num [1:52920] 37 37 37 37 37 37 37 37 37 37 ...
##  $ peak_height      : num [1:52920] 82834 159688 140461 47134 83790 ...
##  $ Subject          : chr [1:52920] "6101" "6110" "6104" "6109" ...
##  $ Period           : chr [1:52920] "U4" "U2" "U2" "U4" ...
##  $ sequence         : chr [1:52920] "R_Y" "Y_R" "Y_R" "Y_R" ...
##  $ Intervention_week: num [1:52920] 14 6 6 14 2 10 2 14 6 6 ...
##  $ Sex              : chr [1:52920] "F" "M" "M" "F" ...
##  $ Age              : num [1:52920] 58 36 54 75 46 36 40 46 61 40 ...
##  $ BMI              : num [1:52920] 31.1 29.9 33.1 43.3 30 ...
# replace NA's in subject and intervention columns with QC
df_combined_sep$Subject <- df_combined_sep$Subject %>%
  replace_na("QC")

df_combined_sep$Intervention <- df_combined_sep$Intervention %>%
  replace_na("QC")

Data summaries

Number of masses detected

nrow(omicsdata)
## [1] 945

Mass range for metabolites detected?

range(df_combined_sep$mz)
## [1]   61.0395 1106.5217

RT range for metabolites detected?

range(df_combined_sep$rt)
## [1]  0.553 10.707

mass vs RT scatterplot

# plot
(plot_mzvsrt <- df_combined_sep %>%
  ggplot(aes(x = rt, y = mz)) +
  geom_point() +
  theme_minimal() +
  labs(x = "Retention time, min",
       y = "m/z, neutral",
       title = "mz across RT for all features"))

Histogram for mass range

df_combined_sep %>%
  ggplot(aes(x = mz)) +
  geom_histogram(binwidth = 25) +
  theme_minimal() +
  labs(x = "Monoisotopic mass (amu)",
       y = "Number of features",
       title = "Distribution of features by mass")

Histogram for RT

df_combined_sep %>%
  ggplot(aes(x = rt)) +
  geom_histogram(binwidth = 0.1) + # 6 second bins
  theme_minimal() +
  labs(x = "Retention time",
       y = "Number of features",
       title = "Distribution of features by retention time")

NAs and imputing

NAs

# NAs in all data including QCs
NAbyRow <- rowSums(is.na(omicsdata[,-1]))

hist(NAbyRow,
     breaks = 56, # because there are 56 samples, 48 samples + 8 QCs
     xlab = "Number of missing values",
     ylab = "Number of metabolites",
     main = "How many missing values are there?")

# samples only (no QCs)
omicsdata_noQC <- omicsdata %>%
 dplyr::select(-contains("QC"))

#NAs in samples only?
NAbyRow_noQC <- rowSums(is.na(omicsdata_noQC[,-1]))

hist(NAbyRow_noQC,
     breaks = 48, # because there are 48 samples 
     xlab = "Number of missing values",
     ylab = "Number of metabolites",
     main = "How many missing values are there?")

Are there any missing values in QCs? There shouldn’t be after data preprocessing/filtering

omicsdata_QC <- omicsdata %>%
 dplyr::select(starts_with("P")) 

NAbyRow_QC <- colSums(is.na(omicsdata_QC))
# lets confirm that there are no missing values from my QCs
sum(NAbyRow_QC) # no
## [1] 0
# calculate how many NAs there are per feature in whole data set
contains_NAs <- df_combined %>%
  group_by(mz_rt) %>%
  count(is.na(peak_height)) %>%
  filter(`is.na(peak_height)` == TRUE)
head(contains_NAs)
## # A tibble: 6 × 3
## # Groups:   mz_rt [6]
##   mz_rt           `is.na(peak_height)`     n
##   <chr>           <lgl>                <int>
## 1 1056.4441_3.056 TRUE                    44
## 2 106.0133_6.888  TRUE                    36
## 3 1071.4352_3.059 TRUE                    44
## 4 1106.5217_3.833 TRUE                    44
## 5 119.0485_0.793  TRUE                    36
## 6 119.0492_3.019  TRUE                    21

NAs by groups

#calculate NAs per feature in red intervention
NAs_Red_Intervention <- df_combined %>%
  group_by(mz_rt) %>%
  filter(Intervention == "Red") %>%
  count(is.na(peak_height)) %>%
  filter(`is.na(peak_height)` == TRUE)

head(NAs_Red_Intervention)
## # A tibble: 6 × 3
## # Groups:   mz_rt [6]
##   mz_rt           `is.na(peak_height)`     n
##   <chr>           <lgl>                <int>
## 1 1056.4441_3.056 TRUE                    22
## 2 106.0133_6.888  TRUE                    15
## 3 1071.4352_3.059 TRUE                    22
## 4 1106.5217_3.833 TRUE                    22
## 5 119.0485_0.793  TRUE                    19
## 6 119.0492_3.019  TRUE                    12
#calculate NAs per feature in yellow intervention
NAs_Yellow_Intervention <- df_combined %>%
  group_by(mz_rt) %>%
  filter(Intervention == "Yellow") %>%
  count(is.na(peak_height)) %>%
  filter(`is.na(peak_height)` == TRUE)

head(NAs_Yellow_Intervention)
## # A tibble: 6 × 3
## # Groups:   mz_rt [6]
##   mz_rt           `is.na(peak_height)`     n
##   <chr>           <lgl>                <int>
## 1 1056.4441_3.056 TRUE                    22
## 2 106.0133_6.888  TRUE                    21
## 3 1071.4352_3.059 TRUE                    22
## 4 1106.5217_3.833 TRUE                    22
## 5 119.0485_0.793  TRUE                    17
## 6 119.0492_3.019  TRUE                     9
#calculate NAs per feature in before both interventions
NAs_preIntervention <- df_combined %>%
  group_by(mz_rt) %>%
  filter(pre_post == "pre") %>%
  count(is.na(peak_height)) %>%
  filter(`is.na(peak_height)` == TRUE)

head(NAs_preIntervention)
## # A tibble: 6 × 3
## # Groups:   mz_rt [6]
##   mz_rt           `is.na(peak_height)`     n
##   <chr>           <lgl>                <int>
## 1 1056.4441_3.056 TRUE                    22
## 2 106.0133_6.888  TRUE                    17
## 3 1071.4352_3.059 TRUE                    22
## 4 1106.5217_3.833 TRUE                    22
## 5 119.0485_0.793  TRUE                    18
## 6 119.0492_3.019  TRUE                    10
#calculate NAs per feature after both interventions
NAs_postIntervention <- df_combined %>%
  group_by(mz_rt) %>%
  filter(pre_post == "post") %>%
  count(is.na(peak_height)) %>%
  filter(`is.na(peak_height)` == TRUE)

head(NAs_postIntervention)
## # A tibble: 6 × 3
## # Groups:   mz_rt [6]
##   mz_rt           `is.na(peak_height)`     n
##   <chr>           <lgl>                <int>
## 1 1056.4441_3.056 TRUE                    22
## 2 106.0133_6.888  TRUE                    19
## 3 1071.4352_3.059 TRUE                    22
## 4 1106.5217_3.833 TRUE                    22
## 5 119.0485_0.793  TRUE                    18
## 6 119.0492_3.019  TRUE                    11

Data imputation

# impute any missing values by replacing them with 1/2 of the lowest peak height value of a feature (i.e. in a row).
imputed_omicsdata <- omicsdata

imputed_omicsdata[] <- lapply(imputed_omicsdata, 
                              function(x) ifelse(is.na(x),
                                                 min(x, na.rm = TRUE)/2, x))

dim(imputed_omicsdata)
## [1] 945  58

Are there any NAs?

imputed_omicsdata %>%
  is.na() %>%
  sum()
## [1] 0
# imputations worked

Create new imputed tidy datasets

# create long df for imputed omics df
imputed_omicsdata_tidy <- imputed_omicsdata %>%
  pivot_longer(cols = 3:ncol(.),
               names_to = "sample_ID",
               values_to = "peak_height")

# combine meta and imputed omics dfs
imputed_fulldata <- full_join(imputed_omicsdata_tidy,
                         metadata,
                         by = c("sample_ID" = "sample_ID"))

# separate mz and rt
imputed_fulldata_sep <- imputed_fulldata %>%
  separate(col = mz_rt,
           into = c("mz", "rt"),
           sep = "_") 

# convert columns to correct type
imputed_fulldata_sep$mz <- as.numeric(imputed_fulldata_sep$mz)
imputed_fulldata_sep$rt <- as.numeric(imputed_fulldata_sep$rt)
imputed_fulldata_sep$Subject <- as.character(imputed_fulldata_sep$Subject)
imputed_fulldata_sep$Intervention <- as.character(imputed_fulldata_sep$Intervention)

Plot features. RT vs mz

# rt vs mz plot
imputed_fulldata_sep %>%
  ggplot(aes(x = rt, y = mz)) +
  geom_point() +
  theme_minimal() +
  labs(x = "RT (min)",
       y = "mz")

Notame feature reduction

vignette for reference

#browseVignettes("notame")

Data restructuring for notame

# create features list from imputed data set to only include unique feature ID's (mz_rt), mz and RT
features <- imputed_fulldata_sep %>%
  cbind(imputed_fulldata$mz_rt) %>%
  rename("mz_rt" = "imputed_fulldata$mz_rt") %>%
 dplyr::select(c(mz_rt, mz, rt)) %>%
  distinct() # remove the duplicate rows

# create a second data frame which is just imputed_fulldata restructured to another wide format
data_notame <- data.frame(imputed_omicsdata %>%
                           dplyr::select(-row_ID) %>%
                            t())

data_notame <- data_notame %>%
  tibble::rownames_to_column() %>% # change samples from rownames to its own column
  row_to_names(row_number = 1) # change the feature IDs (mz_rt) from first row obs into column names

Check structures

# check if mz and rt are numeric
str(features)
## 'data.frame':    945 obs. of  3 variables:
##  $ mz_rt: chr  "226.9516_0.553" "159.1492_0.608" "175.1442_0.616" "189.1684_0.616" ...
##  $ mz   : num  227 159 175 189 189 ...
##  $ rt   : num  0.553 0.608 0.616 0.616 0.615 0.621 0.62 0.633 0.635 0.636 ...
tibble(features)
## # A tibble: 945 × 3
##    mz_rt             mz    rt
##    <chr>          <dbl> <dbl>
##  1 226.9516_0.553  227. 0.553
##  2 159.1492_0.608  159. 0.608
##  3 175.1442_0.616  175. 0.616
##  4 189.1684_0.616  189. 0.616
##  5 189.16_0.615    189. 0.615
##  6 156.0769_0.621  156. 0.621
##  7 170.0926_0.62   170. 0.62 
##  8 136.0482_0.633  136. 0.633
##  9 151.1443_0.635  151. 0.635
## 10 137.071_0.636   137. 0.636
## # ℹ 935 more rows
# check if results are numeric
tibble(data_notame)
## # A tibble: 56 × 946
##    mz_rt     `226.9516_0.553` `159.1492_0.608` `175.1442_0.616` `189.1684_0.616`
##    <chr>     <chr>            <chr>            <chr>            <chr>           
##  1 6101_U4_… "  82834.1800"   "  40852.7970"   "  13575.6550"   "  19074.8930"  
##  2 6110_U2_… " 159688.0300"   "  17948.1500"   "  21984.4790"   "  17190.7050"  
##  3 6104_U2_… " 140460.9000"   "  32255.4550"   "  14964.8470"   "  20831.3890"  
##  4 6109_U4_… "  47134.4200"   "  63559.5400"   "  52516.5600"   "  24691.2460"  
##  5 6111_U1_… "  83789.7700"   " 131795.4400"   "  47572.5400"   "  31355.4630"  
##  6 6110_U3_… " 115715.8700"   "  71032.5500"   "  14294.8420"   "  27822.7420"  
##  7 6105_U1_… " 141117.8600"   "  72057.3500"   "  44426.5080"   "  28435.2440"  
##  8 6111_U4_… " 103462.300"    " 120798.030"    "  50446.316"    "  33316.652"   
##  9 6113_U2_… " 121278.8000"   "  92756.7900"   "  37672.3800"   "  34728.8440"  
## 10 6105_U2_… "  92647.2340"   "  98266.6800"   "  55319.7970"   "  26269.3400"  
## # ℹ 46 more rows
## # ℹ 941 more variables: `189.16_0.615` <chr>, `156.0769_0.621` <chr>,
## #   `170.0926_0.62` <chr>, `136.0482_0.633` <chr>, `151.1443_0.635` <chr>,
## #   `137.071_0.636` <chr>, `182.0574_0.654` <chr>, `162.1126_0.642` <chr>,
## #   `76.0757_0.642` <chr>, `114.0669_0.645` <chr>, `227.1255_0.647` <chr>,
## #   `193.1547_0.646` <chr>, `219.1705_0.65` <chr>, `163.1243_0.654` <chr>,
## #   `213.1234_0.672` <chr>, `203.1502_0.654` <chr>, `138.0551_0.654` <chr>, …
# change to results to numeric
data_notame <- data_notame %>%
  mutate_at(-1, as.numeric)

tibble(data_notame)
## # A tibble: 56 × 946
##    mz_rt     `226.9516_0.553` `159.1492_0.608` `175.1442_0.616` `189.1684_0.616`
##    <chr>                <dbl>            <dbl>            <dbl>            <dbl>
##  1 6101_U4_…           82834.           40853.           13576.           19075.
##  2 6110_U2_…          159688.           17948.           21984.           17191.
##  3 6104_U2_…          140461.           32255.           14965.           20831.
##  4 6109_U4_…           47134.           63560.           52517.           24691.
##  5 6111_U1_…           83790.          131795.           47573.           31355.
##  6 6110_U3_…          115716.           71033.           14295.           27823.
##  7 6105_U1_…          141118.           72057.           44427.           28435.
##  8 6111_U4_…          103462.          120798.           50446.           33317.
##  9 6113_U2_…          121279.           92757.           37672.           34729.
## 10 6105_U2_…           92647.           98267.           55320.           26269.
## # ℹ 46 more rows
## # ℹ 941 more variables: `189.16_0.615` <dbl>, `156.0769_0.621` <dbl>,
## #   `170.0926_0.62` <dbl>, `136.0482_0.633` <dbl>, `151.1443_0.635` <dbl>,
## #   `137.071_0.636` <dbl>, `182.0574_0.654` <dbl>, `162.1126_0.642` <dbl>,
## #   `76.0757_0.642` <dbl>, `114.0669_0.645` <dbl>, `227.1255_0.647` <dbl>,
## #   `193.1547_0.646` <dbl>, `219.1705_0.65` <dbl>, `163.1243_0.654` <dbl>,
## #   `213.1234_0.672` <dbl>, `203.1502_0.654` <dbl>, `138.0551_0.654` <dbl>, …

Find connections

connection <- find_connections(data = data_notame,
                               features = features,
                               corr_thresh = 0.9,
                               rt_window = 1/60,
                               name_col = "mz_rt",
                               mz_col = "mz",
                               rt_col = "rt")
## [1] 100
## [1] 200
## [1] 300
## [1] 400
## [1] 500
## [1] 600
## [1] 700
## [1] 800
## [1] 900
head(connection)
##                x              y       cor rt_diff  mz_diff
## 1 151.1443_0.635  76.0757_0.642 0.9772910   0.007 -75.0686
## 2 182.0574_0.654 287.1967_0.655 0.9865474   0.001 105.1393
## 3 114.0669_0.645 227.1255_0.647 0.9689492   0.002 113.0586
## 4  219.1705_0.65 145.1054_0.656 0.9099522   0.006 -74.0651
## 5 144.1023_0.656 145.1054_0.656 0.9856422   0.000   1.0031
## 6 343.1668_0.698  258.1241_0.69 0.9555601  -0.008 -85.0427

Clustering

clusters <- find_clusters(connections = connection, d_thresh = 0.8)
## 113 components found
## 
## Component 100 / 113 
## 37 components found
## 
## 12 components found
## 
## 9 components found
## 
## 2 components found
## 
## 1 components found
# assign a cluster ID to all features. Clusters are named after feature with highest median peak height
features_clustered <- assign_cluster_id(data_notame, clusters, features, name_col = "mz_rt")

# visualize clusters
#visualize_clusters(data_notame, features, clusters, min_size = 3, rt_window = 2,name_col = "mz_rt", mz_col = "mz", rt_col = "rt", file_path = "~/path/to/project/")

# lets see how many features are removed when we only keep one feature per cluster
pulled <- pull_clusters(data_notame, features_clustered, name_col = "mz_rt")
cluster_data <- pulled$cdata
cluster_features <- pulled$cfeatures
# export clustered feature list
write_csv(cluster_features,
          "notame_dfs/cluster_features-_c18-pos.csv")

nrow(omicsdata) - nrow(cluster_features)
## [1] 317

Reduce dataset based on clustering

# transpose the full dataset back to wide so that it is more similar to the notame dataset
imputed_fulldata_wide <- imputed_fulldata %>%
 dplyr::select(-"row_ID") %>%
  pivot_wider(names_from = mz_rt,
              values_from = peak_height)

# list of reduced features
clusternames <- cluster_features$mz_rt

#dplyr:: only the features are in the reduced list
imp_clust <- imputed_fulldata_wide[,c(names(imputed_fulldata_wide) %in% clusternames)]

# bind back sample names
imp_clust <- cbind(imputed_fulldata_wide[1], imp_clust)

ncol(imp_clust[,-1])
## [1] 628

Mz vs RT scatterplot

# plot new rt vs mz scatterplot post-clustering
(plot_mzvsrt_postcluster <- cluster_features %>%
  ggplot(aes(x = rt,
             y = mz)) +
  geom_point() +
  theme_minimal() +
  labs(x = "Retention time, min",
       y = "m/z, neutral",
       title = "mz across RT for all features after clustering"))

# plot both scatterplots to compare with and without notame clustering
(scatterplots <- ggarrange(plot_mzvsrt, 
                           plot_mzvsrt_postcluster, 
                           nrow = 2))

Bind meta data

imp_metabind_clust <- right_join(metadata, 
                                 imp_clust,
                                 by = "sample_ID")

Visualize untransformed data

Data wrangling

# change meta data columns to character so that I can change NAs from QCs to "QC"
imp_metabind_clust <- imp_metabind_clust %>%
  mutate_at(c("Subject",
              "Period",
              "Intervention",
              "pre_post",
              "sequence",
              "Intervention_week",
              "Sex",
              "Age",
              "BMI"),
            as.character) 

# replace NAs in metadata columns for QCs
imp_metabind_clust[is.na(imp_metabind_clust)] <- "QC"

# unite pre_post column with intervention column to create pre_intervention column
imp_metabind_clust <- imp_metabind_clust %>%
  unite(col = "pre_post_intervention",
        c("pre_post","Intervention"),
        sep = "_",
        remove = FALSE)

# long df
imp_metabind_clust_tidy <- imp_metabind_clust %>%
  pivot_longer(cols = 12:ncol(.),
               names_to = "mz_rt",
               values_to = "rel_abund")

# structure check
str(imp_metabind_clust_tidy)
## tibble [35,168 × 13] (S3: tbl_df/tbl/data.frame)
##  $ sample_ID            : chr [1:35168] "6101_U1_C18POS_59" "6101_U1_C18POS_59" "6101_U1_C18POS_59" "6101_U1_C18POS_59" ...
##  $ Subject              : chr [1:35168] "6101" "6101" "6101" "6101" ...
##  $ Period               : chr [1:35168] "U1" "U1" "U1" "U1" ...
##  $ pre_post_intervention: chr [1:35168] "pre_Red" "pre_Red" "pre_Red" "pre_Red" ...
##  $ Intervention         : chr [1:35168] "Red" "Red" "Red" "Red" ...
##  $ pre_post             : chr [1:35168] "pre" "pre" "pre" "pre" ...
##  $ sequence             : chr [1:35168] "R_Y" "R_Y" "R_Y" "R_Y" ...
##  $ Intervention_week    : chr [1:35168] "2" "2" "2" "2" ...
##  $ Sex                  : chr [1:35168] "F" "F" "F" "F" ...
##  $ Age                  : chr [1:35168] "58" "58" "58" "58" ...
##  $ BMI                  : chr [1:35168] "31.0556029483653" "31.0556029483653" "31.0556029483653" "31.0556029483653" ...
##  $ mz_rt                : chr [1:35168] "226.9516_0.553" "159.1492_0.608" "175.1442_0.616" "189.1684_0.616" ...
##  $ rel_abund            : num [1:35168] 108697 81884 16201 28592 407452 ...

Boxplot

imp_metabind_clust_tidy %>%
  ggplot(aes(x = sample_ID, y = rel_abund, color = Intervention)) +
  geom_boxplot(alpha = 0.6) +
  scale_color_manual(values = c("light grey", "tomato1", "gold")) +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 90)) +
  labs(title = "LC-MS (+) Feature Abundances by Sample",
       subtitle = "Unscaled data",
       y = "Relative abundance")

Will need to log transform in order to normalize and actually see the data

Log2 transform

imp_metabind_clust_tidy_log2 <- imp_metabind_clust_tidy %>%
  mutate(rel_abund_log2 = if_else(rel_abund > 0, log2(rel_abund), 0)) %>%
  replace(is.na(.), 0)

Boxplot

(bp_data_quality <- imp_metabind_clust_tidy_log2 %>%
  ggplot(aes(x = sample_ID, y = rel_abund_log2, fill = Intervention)) +
  geom_boxplot(alpha = 0.6) +
  scale_fill_manual(values = c("light grey", "tomato1", "gold")) +
  theme_minimal() +
  labs(title = "LC-MS (+) Feature Abundances by Sample",
       subtitle = "Log2 transformed data",
       y = "Relative abundance"))

Notame drift correction

Data wrangling

Feature abund df

# filtered and imputed data after notame clustering, transposed
features_testforQCcorr <- t(imp_clust) %>%
  as.data.frame() %>%
  row_to_names(row_number = "find_header")

# log2 transform
log2_features_testforQCcorr <- features_testforQCcorr %>%
  mutate_all(as.numeric) %>%
  log2()

# write csv to manually edit
write.csv(log2_features_testforQCcorr,
          "notame_dfs/feaures_test.csv",
          row.names = TRUE)

Import corrected df (edited so that mz_rt could rowname 1)

# for some reason the r is not recognizing my wd so I'll run file.choose

features_forQCcorr <- read.csv("notame_dfs/feaures_forQCcorr.csv",
                                header = FALSE,
                                row.names = 1)


features_forQCcorr <- features_forQCcorr %>%
  rownames_to_column(var = "mz_rt") %>%
  row_to_names(row_number = 1)%>%
  separate(col = mz_rt,
           into = c("mz", "rt"),
           sep = "_")

write.csv(features_forQCcorr,
          "notame_dfs/features_forQCcorr_pt2.csv",
          row.names = TRUE)

Pheno df

# separate sampleID and injection order
pheno_data <- imp_clust[1] %>%
  separate(col = sample_ID,
           into = c("sample_ID", "injection_order"),
           sep = "_c18POS_")

# fix injection numbers to correct number
pheno_data[54, "injection_order"] <- 9
pheno_data[40, "injection_order"] <- 10
pheno_data[13, "injection_order"] <- 26
pheno_data[24, "injection_order"] <- 27
pheno_data[42, "injection_order"] <- 28
pheno_data[32, "injection_order"] <- 29

# make inj order column numeric
pheno_data <- pheno_data %>%
  mutate_at("injection_order", as.numeric)

t_pheno_data <- as.data.frame(t(pheno_data))

write.csv(t_pheno_data,
          "notame_dfs/pheno_df.csv",
          row.names = TRUE)

Combine pheno and feature dfs manually in excel to create metaboset df.

Import Metaboset

#make sure when converting csv to xlsx that you save as a new file, don't just change the name of the file
metaboset <- read_from_excel("notame_dfs/metaboset.xlsx",
                             split_by = c("column", "Ion mode"))
## INFO [2025-07-31 15:58:41] Detecting corner position
## INFO [2025-07-31 15:58:41] Corner detected correctly at row 3, column D
## INFO [2025-07-31 15:58:41] 
## Extracting sample information from rows 1 to 3 and columns E to BH
## INFO [2025-07-31 15:58:41] Replacing spaces in sample information column names with underscores (_)
## INFO [2025-07-31 15:58:41] Naming the last column of sample information "Datafile"
## INFO [2025-07-31 15:58:41] 
## Extracting feature information from rows 4 to 631 and columns A to D
## INFO [2025-07-31 15:58:41] Creating Split column from column, Ion mode
## INFO [2025-07-31 15:58:41] Feature_ID column not found, creating feature IDs
## INFO [2025-07-31 15:58:41] Identified m/z column mass and retention time column rt
## INFO [2025-07-31 15:58:41] Identified m/z column mass and retention time column rt
## INFO [2025-07-31 15:58:41] Creating feature IDs from Split, m/z and retention time
## INFO [2025-07-31 15:58:41] Replacing dots (.) in feature information column names with underscores (_)
## INFO [2025-07-31 15:58:41] 
## Extracting feature abundances from rows 4 to 631 and columns E to BH
## INFO [2025-07-31 15:58:41] 
## Checking sample information
## INFO [2025-07-31 15:58:41] QC column generated from rows containing 'QC'
## INFO [2025-07-31 15:58:41] Sample ID autogenerated from injection orders and prefix ID_
## INFO [2025-07-31 15:58:41] Checking that feature abundances only contain numeric values
## INFO [2025-07-31 15:58:41] 
## Checking feature information
## INFO [2025-07-31 15:58:41] Checking that feature IDs are unique and not stored as numbers
## INFO [2025-07-31 15:58:41] Checking that m/z and retention time values are reasonable
## INFO [2025-07-31 15:58:41] Identified m/z column mass and retention time column rt
## INFO [2025-07-31 15:58:41] Identified m/z column mass and retention time column rt
#construct Metaboset
modes <- construct_metabosets(exprs = metaboset$exprs,
                              pheno_data = metaboset$pheno_data,
                              feature_data = metaboset$feature_data, group_col = "Class")
## Initializing the object(s) with unflagged features
## INFO [2025-07-31 15:58:41] 
## Checking feature information
## INFO [2025-07-31 15:58:41] Checking that feature IDs are unique and not stored as numbers
## INFO [2025-07-31 15:58:41] Checking that feature abundances only contain numeric values
## INFO [2025-07-31 15:58:41] Setting row and column names of exprs based on feature and pheno data
#extract each mode into a single object
mode <- modes$c18_pos

Boxplots before correction

# ordered by injection
(qualityBPs_b4correction <- plot_sample_boxplots(mode, order_by = "Class", title = "c18 (+) uncorrected feature abundance") +
   scale_fill_manual(values = c("light gray", "deepskyblue2")))

#ordered by class
plot_sample_boxplots(mode, order_by = "Injection_order", title = "Uncorrected feature abundance") +
   scale_fill_manual(values = c("light gray", "deepskyblue2"))

Boxplots after QC drift correction

drift corrected takes up to 2 minutes

mode <- flag_detection(mode, qc_limit = 0.75, group_limit = 0.8)
corrected <- correct_drift(mode, log_transform = FALSE)

Did drift correction work?

output is percent of the features that were drift corrected. The remaining “low-quality” percent represents features for which the DC did not improve the RSD and D-ratio of the original data.

inspected <- inspect_dc(orig = mode, dc = corrected, check_quality = TRUE)

Boxplots, corrected

(qualityBPS_driftcorrection <- plot_sample_boxplots(corrected, order_by = "Class", title = "c18 (+) drift-corrected feature abundance") +
   scale_fill_manual(values = c("light gray", "deepskyblue2")))

plot_sample_boxplots(corrected, order_by = "Injection_order", title = "Corrected feature abundance")

Compare quality BPs

(qualityBPs_compared <- ggarrange(qualityBPs_b4correction, qualityBPS_driftcorrection,
                    ncol = 2, nrow = 1))

Export new Metaboset to Excel spreadsheet

write_to_excel(corrected, "notame_dfs/metaboset_corrected.xlsx")

Import edited Metaboset

metabdata_corrected <- read.csv(file = "notame_dfs/metaboset_corrected_editedforR.csv",
                                check.names = FALSE)

Wrangle new metab data

Combine mz & rt back together

metabdata_corrected_MZ_RT <- metabdata_corrected %>%
  mutate(mass = round(metabdata_corrected$mass, digits = 4), # Decrease number of decimals for m/z & rt
         rt = round(metabdata_corrected$rt, digits = 3),
         .before=1,
         .keep="unused") %>%
  unite(mz_rt, c(mass, rt), remove=TRUE) # Combine m/z & rt with _ in between

Transpose new df

metabdata_corrected_t <- as.data.frame(t(metabdata_corrected_MZ_RT)) %>%
  row_to_names(row_number = "find_header") %>% # make MZ_RT column names
  rownames_to_column(var = "subj_period") # change rownames to column 1

Bind new data with metadata

I want the new drift corrected (DC) df to look just like “imp_metabind_clust_log2” df

# go back to wide data
imp_metabind_clust_log2 <- imp_metabind_clust_tidy_log2 %>%
  dplyr::select(!rel_abund) %>%
  pivot_wider(names_from = mz_rt,
              values_from = rel_abund_log2)
# combine subject and period columns from imp_metabind_clust_log2 in order to mimic DC df
subj_per_imp_metabind_clust_log2 <- imp_metabind_clust_log2 %>%
  unite(subj_period, c(Subject, Period), remove = FALSE)

# place new DC observations in
DC_imp_metabind_clust_log2 <- full_join(subj_per_imp_metabind_clust_log2[,c(1:12)], metabdata_corrected_t, by = "subj_period")

# take out old QC observations
DC_imp_metabind_clust_log2 <- DC_imp_metabind_clust_log2 %>%
  filter(subj_period != "QC_QC")

# replace NAs in columns for QCs
DC_imp_metabind_clust_log2[is.na(DC_imp_metabind_clust_log2)] <- "QC"
#tidy df
DC_imp_metabind_clust_tidy_log2 <- DC_imp_metabind_clust_log2 %>%
  pivot_longer(13:ncol(.),
               names_to = "mz_rt",
               values_to = "rel_abund_log2") %>%
  mutate_at("rel_abund_log2", as.numeric)

Load Feature ID Key

Here, I’m inserting a key that would indicate identified features at level 3 ID or higher.

key_omics <- read_xlsx("../annotated-features-table.xlsx",
                 sheet = "Features") %>%
  clean_names() %>%
  filter(lc_mode_c18_hilic == "C18") %>% # LC mode
  filter(esi_mode == "+") %>% # ESI mode
  dplyr::select(mz_rt, annotation, metabolite_class, parent_compound) # select relevant columns

# add key columns (left_join to only keep all observations present in full feature table)
anno_imp_metabind_clust_tidy_log2 <- left_join(DC_imp_metabind_clust_tidy_log2, key_omics, by = "mz_rt") %>%
  # replace NAs in feature ID columns to un-annotated feature id's (mz_rt)
  mutate(Feature_ID = coalesce(annotation, mz_rt))

PCAs

With QCS

Wrangle

# go back to wide data
anno_imp_metabind_clust_log2 <- anno_imp_metabind_clust_tidy_log2 %>%
  dplyr::select(c(1:11),
                Feature_ID, rel_abund_log2) %>%
  pivot_wider(names_from = Feature_ID,
              values_from = rel_abund_log2) 
PCA.DC_imp_metabind_clust_log2 <- PCA(anno_imp_metabind_clust_log2,  # wide data
                                   quali.sup = 1:11, # remove qualitative variables
                                   graph = FALSE, # don't graph
                                   scale.unit = FALSE) # don't scale, already transformed data

# PCA summary
kable(summary(PCA.DC_imp_metabind_clust_log2))
## 
## Call:
## PCA(X = anno_imp_metabind_clust_log2, scale.unit = FALSE, quali.sup = 1:11,  
##      graph = FALSE) 
## 
## 
## Eigenvalues
##                        Dim.1   Dim.2   Dim.3   Dim.4   Dim.5   Dim.6   Dim.7
## Variance             683.902 247.574 104.066  71.119  61.213  50.743  41.782
## % of var.             42.958  15.551   6.537   4.467   3.845   3.187   2.624
## Cumulative % of var.  42.958  58.509  65.045  69.513  73.357  76.545  79.169
##                        Dim.8   Dim.9  Dim.10  Dim.11  Dim.12  Dim.13  Dim.14
## Variance              34.622  28.155  25.591  23.197  21.062  17.007  16.217
## % of var.              2.175   1.768   1.607   1.457   1.323   1.068   1.019
## Cumulative % of var.  81.344  83.112  84.720  86.177  87.500  88.568  89.587
##                       Dim.15  Dim.16  Dim.17  Dim.18  Dim.19  Dim.20  Dim.21
## Variance              12.253  11.014  10.922   9.426   9.061   8.556   7.560
## % of var.              0.770   0.692   0.686   0.592   0.569   0.537   0.475
## Cumulative % of var.  90.356  91.048  91.734  92.326  92.896  93.433  93.908
##                       Dim.22  Dim.23  Dim.24  Dim.25  Dim.26  Dim.27  Dim.28
## Variance               6.762   6.667   6.434   5.911   5.234   5.011   4.769
## % of var.              0.425   0.419   0.404   0.371   0.329   0.315   0.300
## Cumulative % of var.  94.332  94.751  95.155  95.527  95.855  96.170  96.470
##                       Dim.29  Dim.30  Dim.31  Dim.32  Dim.33  Dim.34  Dim.35
## Variance               4.426   4.391   4.032   3.758   3.644   3.348   3.058
## % of var.              0.278   0.276   0.253   0.236   0.229   0.210   0.192
## Cumulative % of var.  96.748  97.024  97.277  97.513  97.742  97.952  98.144
##                       Dim.36  Dim.37  Dim.38  Dim.39  Dim.40  Dim.41  Dim.42
## Variance               3.027   2.796   2.600   2.505   2.456   2.352   2.259
## % of var.              0.190   0.176   0.163   0.157   0.154   0.148   0.142
## Cumulative % of var.  98.334  98.510  98.673  98.831  98.985  99.133  99.274
##                       Dim.43  Dim.44  Dim.45  Dim.46  Dim.47  Dim.48  Dim.49
## Variance               2.131   1.959   1.782   1.670   1.499   1.445   0.318
## % of var.              0.134   0.123   0.112   0.105   0.094   0.091   0.020
## Cumulative % of var.  99.408  99.531  99.643  99.748  99.842  99.933  99.953
##                       Dim.50  Dim.51  Dim.52  Dim.53  Dim.54  Dim.55
## Variance               0.191   0.178   0.158   0.148   0.073   0.000
## % of var.              0.012   0.011   0.010   0.009   0.005   0.000
## Cumulative % of var.  99.965  99.976  99.986  99.995 100.000 100.000
## 
## Individuals (the 10 first)
##                                                                Dist     Dim.1
## 1                                                         |  29.831 | -20.616
## 2                                                         |  27.573 | -20.316
## 3                                                         |  30.832 | -10.133
## 4                                                         |  29.309 | -19.939
## 5                                                         |  29.451 | -17.509
## 6                                                         |  65.518 |  48.818
## 7                                                         |  32.386 | -17.632
## 8                                                         |  27.196 | -14.505
## 9                                                         |  25.206 | -13.566
## 10                                                        |  31.113 | -13.405
##                                                               ctr    cos2  
## 1                                                           1.110   0.478 |
## 2                                                           1.078   0.543 |
## 3                                                           0.268   0.108 |
## 4                                                           1.038   0.463 |
## 5                                                           0.800   0.353 |
## 6                                                           6.223   0.555 |
## 7                                                           0.812   0.296 |
## 8                                                           0.549   0.284 |
## 9                                                           0.481   0.290 |
## 10                                                          0.469   0.186 |
##                                                             Dim.2     ctr
## 1                                                          -5.138   0.190
## 2                                                          -5.252   0.199
## 3                                                          -1.549   0.017
## 4                                                          -2.943   0.062
## 5                                                          -3.955   0.113
## 6                                                         -34.458   8.564
## 7                                                          -2.927   0.062
## 8                                                          -4.137   0.123
## 9                                                          -3.434   0.085
## 10                                                         -1.236   0.011
##                                                              cos2     Dim.3
## 1                                                           0.030 |  -2.862
## 2                                                           0.036 |  -4.679
## 3                                                           0.003 |  -0.393
## 4                                                           0.010 |  -2.200
## 5                                                           0.018 |  -3.079
## 6                                                           0.277 | -15.383
## 7                                                           0.008 |  -2.138
## 8                                                           0.023 |  -3.382
## 9                                                           0.019 |   3.566
## 10                                                          0.002 |  -7.102
##                                                               ctr    cos2  
## 1                                                           0.141   0.009 |
## 2                                                           0.376   0.029 |
## 3                                                           0.003   0.000 |
## 4                                                           0.083   0.006 |
## 5                                                           0.163   0.011 |
## 6                                                           4.061   0.055 |
## 7                                                           0.078   0.004 |
## 8                                                           0.196   0.015 |
## 9                                                           0.218   0.020 |
## 10                                                          0.866   0.052 |
## 
## Variables (the 10 first)
##                                                              Dim.1    ctr
## 226.9516_0.553                                            | -0.060  0.001
## 159.1492_0.608                                            | -0.520  0.040
## 175.1442_0.616                                            |  0.032  0.000
## 189.1684_0.616                                            | -0.053  0.000
## 189.16_0.615                                              | -0.023  0.000
## 156.0769_0.621                                            | -0.011  0.000
## 170.0926_0.62                                             | -0.104  0.002
## 136.0482_0.633                                            |  0.014  0.000
## 137.071_0.636                                             |  0.039  0.000
## 162.1126_0.642                                            |  0.106  0.002
##                                                             cos2    Dim.2
## 226.9516_0.553                                             0.014 |  0.106
## 159.1492_0.608                                             0.329 | -0.298
## 175.1442_0.616                                             0.001 |  0.341
## 189.1684_0.616                                             0.007 |  0.008
## 189.16_0.615                                               0.002 | -0.006
## 156.0769_0.621                                             0.000 | -0.071
## 170.0926_0.62                                              0.012 | -0.052
## 136.0482_0.633                                             0.000 | -0.037
## 137.071_0.636                                              0.006 |  0.141
## 162.1126_0.642                                             0.010 | -0.216
##                                                              ctr   cos2  
## 226.9516_0.553                                             0.005  0.043 |
## 159.1492_0.608                                             0.036  0.108 |
## 175.1442_0.616                                             0.047  0.159 |
## 189.1684_0.616                                             0.000  0.000 |
## 189.16_0.615                                               0.000  0.000 |
## 156.0769_0.621                                             0.002  0.007 |
## 170.0926_0.62                                              0.001  0.003 |
## 136.0482_0.633                                             0.001  0.003 |
## 137.071_0.636                                              0.008  0.071 |
## 162.1126_0.642                                             0.019  0.041 |
##                                                            Dim.3    ctr   cos2
## 226.9516_0.553                                             0.032  0.001  0.004
## 159.1492_0.608                                            -0.081  0.006  0.008
## 175.1442_0.616                                            -0.195  0.036  0.052
## 189.1684_0.616                                             0.140  0.019  0.051
## 189.16_0.615                                              -0.058  0.003  0.011
## 156.0769_0.621                                            -0.027  0.001  0.001
## 170.0926_0.62                                              0.288  0.080  0.089
## 136.0482_0.633                                             0.068  0.004  0.011
## 137.071_0.636                                              0.012  0.000  0.001
## 162.1126_0.642                                             0.274  0.072  0.066
##                                                            
## 226.9516_0.553                                            |
## 159.1492_0.608                                            |
## 175.1442_0.616                                            |
## 189.1684_0.616                                            |
## 189.16_0.615                                              |
## 156.0769_0.621                                            |
## 170.0926_0.62                                             |
## 136.0482_0.633                                            |
## 137.071_0.636                                             |
## 162.1126_0.642                                            |
## 
## Supplementary categories (the 10 first)
##                                                                Dist     Dim.1
## sample_ID_6101_U1_C18POS_59                               |  29.831 | -20.616
## sample_ID_6101_U2_C18POS_30                               |  33.739 | -15.996
## sample_ID_6101_U3_C18POS_29_1                             |  28.213 | -19.582
## sample_ID_6101_U4_C18POS_14                               |  29.307 | -19.516
## sample_ID_6102_U1_C18POS_26_1                             |  27.573 | -20.316
## sample_ID_6102_U2_C18POS_16                               |  26.916 | -15.644
## sample_ID_6102_U3_C18POS_48                               |  35.629 | -13.369
## sample_ID_6102_U4_C18POS_50                               |  26.846 | -15.989
## sample_ID_6103_U1_C18POS_21                               |  30.832 | -10.133
## sample_ID_6103_U2_C18POS_60                               |  33.584 | -14.463
##                                                              cos2  v.test  
## sample_ID_6101_U1_C18POS_59                                 0.478  -0.788 |
## sample_ID_6101_U2_C18POS_30                                 0.225  -0.612 |
## sample_ID_6101_U3_C18POS_29_1                               0.482  -0.749 |
## sample_ID_6101_U4_C18POS_14                                 0.443  -0.746 |
## sample_ID_6102_U1_C18POS_26_1                               0.543  -0.777 |
## sample_ID_6102_U2_C18POS_16                                 0.338  -0.598 |
## sample_ID_6102_U3_C18POS_48                                 0.141  -0.511 |
## sample_ID_6102_U4_C18POS_50                                 0.355  -0.611 |
## sample_ID_6103_U1_C18POS_21                                 0.108  -0.387 |
## sample_ID_6103_U2_C18POS_60                                 0.185  -0.553 |
##                                                             Dim.2    cos2
## sample_ID_6101_U1_C18POS_59                                -5.138   0.030
## sample_ID_6101_U2_C18POS_30                                -3.239   0.009
## sample_ID_6101_U3_C18POS_29_1                              -4.777   0.029
## sample_ID_6101_U4_C18POS_14                                -4.083   0.019
## sample_ID_6102_U1_C18POS_26_1                              -5.252   0.036
## sample_ID_6102_U2_C18POS_16                                -2.420   0.008
## sample_ID_6102_U3_C18POS_48                                 0.584   0.000
## sample_ID_6102_U4_C18POS_50                                -2.253   0.007
## sample_ID_6103_U1_C18POS_21                                -1.549   0.003
## sample_ID_6103_U2_C18POS_60                                -1.448   0.002
##                                                            v.test     Dim.3
## sample_ID_6101_U1_C18POS_59                                -0.327 |  -2.862
## sample_ID_6101_U2_C18POS_30                                -0.206 |   8.201
## sample_ID_6101_U3_C18POS_29_1                              -0.304 |  -2.304
## sample_ID_6101_U4_C18POS_14                                -0.260 |  -2.065
## sample_ID_6102_U1_C18POS_26_1                              -0.334 |  -4.679
## sample_ID_6102_U2_C18POS_16                                -0.154 |   7.097
## sample_ID_6102_U3_C18POS_48                                 0.037 |   1.997
## sample_ID_6102_U4_C18POS_50                                -0.143 |  -1.443
## sample_ID_6103_U1_C18POS_21                                -0.098 |  -0.393
## sample_ID_6103_U2_C18POS_60                                -0.092 |   8.967
##                                                              cos2  v.test  
## sample_ID_6101_U1_C18POS_59                                 0.009  -0.281 |
## sample_ID_6101_U2_C18POS_30                                 0.059   0.804 |
## sample_ID_6101_U3_C18POS_29_1                               0.007  -0.226 |
## sample_ID_6101_U4_C18POS_14                                 0.005  -0.202 |
## sample_ID_6102_U1_C18POS_26_1                               0.029  -0.459 |
## sample_ID_6102_U2_C18POS_16                                 0.070   0.696 |
## sample_ID_6102_U3_C18POS_48                                 0.003   0.196 |
## sample_ID_6102_U4_C18POS_50                                 0.003  -0.141 |
## sample_ID_6103_U1_C18POS_21                                 0.000  -0.038 |
## sample_ID_6103_U2_C18POS_60                                 0.071   0.879 |
Dist Dim.1 cos2 v.test Dim.2 cos2 v.test Dim.3 cos2 v.test
sample_ID_6101_U1_C18POS_59 | 29.831 | -20.616 0.478 -0.788 | -5.138 0.030 -0.327 | -2.862 0.009 -0.281 |
sample_ID_6101_U2_C18POS_30 | 33.739 | -15.996 0.225 -0.612 | -3.239 0.009 -0.206 | 8.201 0.059 0.804 |
sample_ID_6101_U3_C18POS_29_1 | 28.213 | -19.582 0.482 -0.749 | -4.777 0.029 -0.304 | -2.304 0.007 -0.226 |
sample_ID_6101_U4_C18POS_14 | 29.307 | -19.516 0.443 -0.746 | -4.083 0.019 -0.260 | -2.065 0.005 -0.202 |
sample_ID_6102_U1_C18POS_26_1 | 27.573 | -20.316 0.543 -0.777 | -5.252 0.036 -0.334 | -4.679 0.029 -0.459 |
sample_ID_6102_U2_C18POS_16 | 26.916 | -15.644 0.338 -0.598 | -2.420 0.008 -0.154 | 7.097 0.070 0.696 |
sample_ID_6102_U3_C18POS_48 | 35.629 | -13.369 0.141 -0.511 | 0.584 0.000 0.037 | 1.997 0.003 0.196 |
sample_ID_6102_U4_C18POS_50 | 26.846 | -15.989 0.355 -0.611 | -2.253 0.007 -0.143 | -1.443 0.003 -0.141 |
sample_ID_6103_U1_C18POS_21 | 30.832 | -10.133 0.108 -0.387 | -1.549 0.003 -0.098 | -0.393 0.000 -0.038 |
sample_ID_6103_U2_C18POS_60 | 33.584 | -14.463 0.185 -0.553 | -1.448 0.002 -0.092 | 8.967 0.071 0.879 |
# pull PC coordinates into df
PC_coord_QC_log2 <- as.data.frame(PCA.DC_imp_metabind_clust_log2$ind$coord)

# bind back metadata from cols 1-10
PC_coord_QC_log2 <- bind_cols(anno_imp_metabind_clust_log2[,1:11], PC_coord_QC_log2)

# grab some variance explained
importance_QC <- PCA.DC_imp_metabind_clust_log2$eig

# set variance explained with PC1, round to 2 digits
PC1_withQC <- round(importance_QC[1,2], 2)

# set variance explained with PC2, round to 2 digits
PC2_withQC <- round(importance_QC[2,2], 2)

Plots

Using FactoExtra package

# scree plot
fviz_eig(PCA.DC_imp_metabind_clust_log2)

# get eigenvalues
kable(get_eig(PCA.DC_imp_metabind_clust_log2))
eigenvalue variance.percent cumulative.variance.percent
Dim.1 683.9018350 42.9578232 42.95782
Dim.2 247.5739259 15.5508238 58.50865
Dim.3 104.0663840 6.5367061 65.04535
Dim.4 71.1186431 4.4671646 69.51252
Dim.5 61.2125083 3.8449321 73.35745
Dim.6 50.7432449 3.1873278 76.54478
Dim.7 41.7815783 2.6244200 79.16920
Dim.8 34.6220192 2.1747077 81.34391
Dim.9 28.1545052 1.7684647 83.11237
Dim.10 25.5909303 1.6074393 84.71981
Dim.11 23.1967496 1.4570539 86.17686
Dim.12 21.0622589 1.3229805 87.49984
Dim.13 17.0067675 1.0682435 88.56809
Dim.14 16.2173468 1.0186578 89.58675
Dim.15 12.2532775 0.7696633 90.35641
Dim.16 11.0141758 0.6918318 91.04824
Dim.17 10.9220212 0.6860433 91.73428
Dim.18 9.4259369 0.5920700 92.32635
Dim.19 9.0611230 0.5691550 92.89551
Dim.20 8.5555767 0.5374002 93.43291
Dim.21 7.5595219 0.4748351 93.90774
Dim.22 6.7618090 0.4247285 94.33247
Dim.23 6.6673590 0.4187958 94.75127
Dim.24 6.4343824 0.4041619 95.15543
Dim.25 5.9106377 0.3712640 95.52669
Dim.26 5.2343762 0.3287861 95.85548
Dim.27 5.0110426 0.3147579 96.17024
Dim.28 4.7692869 0.2995725 96.46981
Dim.29 4.4255192 0.2779795 96.74779
Dim.30 4.3907598 0.2757961 97.02359
Dim.31 4.0323478 0.2532833 97.27687
Dim.32 3.7576956 0.2360316 97.51290
Dim.33 3.6443434 0.2289116 97.74181
Dim.34 3.3478394 0.2102873 97.95210
Dim.35 3.0581248 0.1920895 98.14419
Dim.36 3.0269329 0.1901303 98.33432
Dim.37 2.7960437 0.1756275 98.50995
Dim.38 2.5999216 0.1633085 98.67326
Dim.39 2.5045627 0.1573187 98.83057
Dim.40 2.4556572 0.1542468 98.98482
Dim.41 2.3524285 0.1477627 99.13258
Dim.42 2.2591637 0.1419045 99.27449
Dim.43 2.1308919 0.1338474 99.40834
Dim.44 1.9585097 0.1230196 99.53136
Dim.45 1.7816994 0.1119136 99.64327
Dim.46 1.6695074 0.1048665 99.74814
Dim.47 1.4992727 0.0941736 99.84231
Dim.48 1.4451116 0.0907716 99.93308
Dim.49 0.3180101 0.0199751 99.95306
Dim.50 0.1910025 0.0119974 99.96505
Dim.51 0.1781614 0.0111908 99.97624
Dim.52 0.1576564 0.0099028 99.98615
Dim.53 0.1477544 0.0092809 99.99543
Dim.54 0.0727906 0.0045722 100.00000
Dim.55 0.0000037 0.0000002 100.00000
# scores plot
fviz_pca_ind(PCA.DC_imp_metabind_clust_log2)

Manual scores plots

# manual scores plot
(PCA_withQCs <- PC_coord_QC_log2 %>%
  ggplot(aes(x = Dim.1, y = Dim.2,
             fill = factor(Intervention, levels = c("Yellow", "Red", "QC")))) +
  geom_point(shape = 21, alpha = 0.8) +
  scale_fill_manual(values = c("gold", "tomato1", "light grey")) +
  scale_color_manual(values = "black") +  
  theme_minimal() +
  coord_fixed(PC2_withQC/PC1_withQC) +
  labs(x = glue::glue("PC1: {PC1_withQC}%"),
       y = glue::glue("PC2: {PC2_withQC}%"),
       fill = "Group",
       title = "Principal Components Analysis Scores Plot",
       subtitle = "Log2 transformed data"))

Without QCs

Wrangle

anno_imp_metabind_clust_log2_noQCs <- anno_imp_metabind_clust_log2 %>%
  filter(Intervention != "QC")

PCA.DC_imp_metabind_clust_log2_noQCs <- PCA(anno_imp_metabind_clust_log2_noQCs, # wide data
                               quali.sup=1:11, # remove qualitative variables
                               graph=FALSE, # don't graph
                               scale.unit=FALSE) # don't scale, we already did this

# look at summary
kable(summary(PCA.DC_imp_metabind_clust_log2_noQCs))
## 
## Call:
## PCA(X = anno_imp_metabind_clust_log2_noQCs, scale.unit = FALSE,  
##      quali.sup = 1:11, graph = FALSE) 
## 
## 
## Eigenvalues
##                        Dim.1   Dim.2   Dim.3   Dim.4   Dim.5   Dim.6   Dim.7
## Variance             441.833 212.422  85.731  80.113  59.413  51.306  45.168
## % of var.             33.213  15.968   6.444   6.022   4.466   3.857   3.395
## Cumulative % of var.  33.213  49.180  55.625  61.647  66.113  69.970  73.365
##                        Dim.8   Dim.9  Dim.10  Dim.11  Dim.12  Dim.13  Dim.14
## Variance              34.113  29.960  27.706  25.293  19.946  18.931  17.610
## % of var.              2.564   2.252   2.083   1.901   1.499   1.423   1.324
## Cumulative % of var.  75.929  78.181  80.264  82.165  83.665  85.088  86.411
##                       Dim.15  Dim.16  Dim.17  Dim.18  Dim.19  Dim.20  Dim.21
## Variance              13.981  12.769  11.055  10.570  10.091   9.072   8.181
## % of var.              1.051   0.960   0.831   0.795   0.759   0.682   0.615
## Cumulative % of var.  87.462  88.422  89.253  90.048  90.806  91.488  92.103
##                       Dim.22  Dim.23  Dim.24  Dim.25  Dim.26  Dim.27  Dim.28
## Variance               7.888   7.504   6.922   6.385   5.991   5.614   5.164
## % of var.              0.593   0.564   0.520   0.480   0.450   0.422   0.388
## Cumulative % of var.  92.696  93.260  93.780  94.260  94.711  95.133  95.521
##                       Dim.29  Dim.30  Dim.31  Dim.32  Dim.33  Dim.34  Dim.35
## Variance               5.135   4.702   4.388   4.250   3.904   3.570   3.553
## % of var.              0.386   0.353   0.330   0.319   0.293   0.268   0.267
## Cumulative % of var.  95.907  96.260  96.590  96.910  97.203  97.471  97.739
##                       Dim.36  Dim.37  Dim.38  Dim.39  Dim.40  Dim.41  Dim.42
## Variance               3.338   3.092   2.969   2.906   2.788   2.652   2.510
## % of var.              0.251   0.232   0.223   0.218   0.210   0.199   0.189
## Cumulative % of var.  97.989  98.222  98.445  98.664  98.873  99.072  99.261
##                       Dim.43  Dim.44  Dim.45  Dim.46  Dim.47
## Variance               2.296   2.110   1.953   1.767   1.704
## % of var.              0.173   0.159   0.147   0.133   0.128
## Cumulative % of var.  99.434  99.592  99.739  99.872 100.000
## 
## Individuals (the 10 first)
##                                                               Dist    Dim.1
## 1                                                         | 24.673 | -9.190
## 2                                                         | 21.767 | -8.370
## 3                                                         | 29.267 | -2.553
## 4                                                         | 24.488 | -9.865
## 5                                                         | 25.247 | -7.014
## 6                                                         | 70.409 | 66.408
## 7                                                         | 28.585 | -7.483
## 8                                                         | 23.553 | -4.287
## 9                                                         | 21.985 | -4.779
## 10                                                        | 28.428 | -4.512
##                                                              ctr   cos2  
## 1                                                          0.398  0.139 |
## 2                                                          0.330  0.148 |
## 3                                                          0.031  0.008 |
## 4                                                          0.459  0.162 |
## 5                                                          0.232  0.077 |
## 6                                                         20.794  0.890 |
## 7                                                          0.264  0.069 |
## 8                                                          0.087  0.033 |
## 9                                                          0.108  0.047 |
## 10                                                         0.096  0.025 |
##                                                            Dim.2    ctr   cos2
## 1                                                         -7.502  0.552  0.092
## 2                                                         -6.285  0.387  0.083
## 3                                                         -1.485  0.022  0.003
## 4                                                         -5.820  0.332  0.056
## 5                                                         -4.946  0.240  0.038
## 6                                                          2.369  0.055  0.001
## 7                                                         -4.034  0.160  0.020
## 8                                                         -3.661  0.131  0.024
## 9                                                         -5.390  0.285  0.060
## 10                                                         0.271  0.001  0.000
##                                                              Dim.3    ctr
## 1                                                         | -9.728  2.300
## 2                                                         | -8.551  1.777
## 3                                                         | -0.811  0.016
## 4                                                         | -7.909  1.520
## 5                                                         | -5.180  0.652
## 6                                                         | -8.327  1.685
## 7                                                         | -9.038  1.985
## 8                                                         | -3.914  0.372
## 9                                                         |  5.090  0.630
## 10                                                        | -7.668  1.429
##                                                             cos2  
## 1                                                          0.155 |
## 2                                                          0.154 |
## 3                                                          0.001 |
## 4                                                          0.104 |
## 5                                                          0.042 |
## 6                                                          0.014 |
## 7                                                          0.100 |
## 8                                                          0.028 |
## 9                                                          0.054 |
## 10                                                         0.073 |
## 
## Variables (the 10 first)
##                                                              Dim.1    ctr
## 226.9516_0.553                                            | -0.162  0.006
## 159.1492_0.608                                            | -0.083  0.002
## 175.1442_0.616                                            | -0.124  0.004
## 189.1684_0.616                                            | -0.087  0.002
## 189.16_0.615                                              | -0.036  0.000
## 156.0769_0.621                                            | -0.039  0.000
## 170.0926_0.62                                             | -0.208  0.010
## 136.0482_0.633                                            |  0.007  0.000
## 137.071_0.636                                             | -0.056  0.001
## 162.1126_0.642                                            |  0.050  0.001
##                                                             cos2    Dim.2
## 226.9516_0.553                                             0.088 | -0.001
## 159.1492_0.608                                             0.012 | -0.236
## 175.1442_0.616                                             0.018 |  0.419
## 189.1684_0.616                                             0.017 | -0.089
## 189.16_0.615                                               0.004 | -0.024
## 156.0769_0.621                                             0.002 | -0.145
## 170.0926_0.62                                              0.040 | -0.333
## 136.0482_0.633                                             0.000 | -0.078
## 137.071_0.636                                              0.010 |  0.125
## 162.1126_0.642                                             0.002 | -0.412
##                                                              ctr   cos2  
## 226.9516_0.553                                             0.000  0.000 |
## 159.1492_0.608                                             0.026  0.094 |
## 175.1442_0.616                                             0.083  0.207 |
## 189.1684_0.616                                             0.004  0.018 |
## 189.16_0.615                                               0.000  0.002 |
## 156.0769_0.621                                             0.010  0.024 |
## 170.0926_0.62                                              0.052  0.103 |
## 136.0482_0.633                                             0.003  0.012 |
## 137.071_0.636                                              0.007  0.049 |
## 162.1126_0.642                                             0.080  0.133 |
##                                                            Dim.3    ctr   cos2
## 226.9516_0.553                                            -0.044  0.002  0.006
## 159.1492_0.608                                            -0.091  0.010  0.014
## 175.1442_0.616                                            -0.022  0.001  0.001
## 189.1684_0.616                                             0.060  0.004  0.008
## 189.16_0.615                                              -0.105  0.013  0.031
## 156.0769_0.621                                            -0.179  0.037  0.036
## 170.0926_0.62                                             -0.104  0.013  0.010
## 136.0482_0.633                                            -0.025  0.001  0.001
## 137.071_0.636                                             -0.003  0.000  0.000
## 162.1126_0.642                                            -0.265  0.082  0.055
##                                                            
## 226.9516_0.553                                            |
## 159.1492_0.608                                            |
## 175.1442_0.616                                            |
## 189.1684_0.616                                            |
## 189.16_0.615                                              |
## 156.0769_0.621                                            |
## 170.0926_0.62                                             |
## 136.0482_0.633                                            |
## 137.071_0.636                                             |
## 162.1126_0.642                                            |
## 
## Supplementary categories (the 10 first)
##                                                               Dist    Dim.1
## 6101_U1_C18POS_59                                         | 24.673 | -9.190
## 6101_U2_C18POS_30                                         | 31.022 | -7.697
## 6101_U3_C18POS_29_1                                       | 23.104 | -8.563
## 6101_U4_C18POS_14                                         | 24.577 | -9.044
## 6102_U1_C18POS_26_1                                       | 21.767 | -8.370
## 6102_U2_C18POS_16                                         | 23.410 | -7.332
## 6102_U3_C18POS_48                                         | 33.928 | -7.323
## 6102_U4_C18POS_50                                         | 23.082 | -7.190
## 6103_U1_C18POS_21                                         | 29.267 | -2.553
## 6103_U2_C18POS_60                                         | 31.321 | -7.237
##                                                             cos2 v.test  
## 6101_U1_C18POS_59                                          0.139 -0.437 |
## 6101_U2_C18POS_30                                          0.062 -0.366 |
## 6101_U3_C18POS_29_1                                        0.137 -0.407 |
## 6101_U4_C18POS_14                                          0.135 -0.430 |
## 6102_U1_C18POS_26_1                                        0.148 -0.398 |
## 6102_U2_C18POS_16                                          0.098 -0.349 |
## 6102_U3_C18POS_48                                          0.047 -0.348 |
## 6102_U4_C18POS_50                                          0.097 -0.342 |
## 6103_U1_C18POS_21                                          0.008 -0.121 |
## 6103_U2_C18POS_60                                          0.053 -0.344 |
##                                                            Dim.2   cos2 v.test
## 6101_U1_C18POS_59                                         -7.502  0.092 -0.515
## 6101_U2_C18POS_30                                         -8.210  0.070 -0.563
## 6101_U3_C18POS_29_1                                       -6.971  0.091 -0.478
## 6101_U4_C18POS_14                                         -6.798  0.077 -0.466
## 6102_U1_C18POS_26_1                                       -6.285  0.083 -0.431
## 6102_U2_C18POS_16                                         -6.343  0.073 -0.435
## 6102_U3_C18POS_48                                         -3.185  0.009 -0.219
## 6102_U4_C18POS_50                                         -4.348  0.035 -0.298
## 6103_U1_C18POS_21                                         -1.485  0.003 -0.102
## 6103_U2_C18POS_60                                         -6.156  0.039 -0.422
##                                                              Dim.3   cos2
## 6101_U1_C18POS_59                                         | -9.728  0.155
## 6101_U2_C18POS_30                                         |  8.542  0.076
## 6101_U3_C18POS_29_1                                       | -7.504  0.105
## 6101_U4_C18POS_14                                         | -8.527  0.120
## 6102_U1_C18POS_26_1                                       | -8.551  0.154
## 6102_U2_C18POS_16                                         | 11.340  0.235
## 6102_U3_C18POS_48                                         | -8.579  0.064
## 6102_U4_C18POS_50                                         | -7.807  0.114
## 6103_U1_C18POS_21                                         | -0.811  0.001
## 6103_U2_C18POS_60                                         | 14.503  0.214
##                                                           v.test  
## 6101_U1_C18POS_59                                         -1.051 |
## 6101_U2_C18POS_30                                          0.923 |
## 6101_U3_C18POS_29_1                                       -0.810 |
## 6101_U4_C18POS_14                                         -0.921 |
## 6102_U1_C18POS_26_1                                       -0.923 |
## 6102_U2_C18POS_16                                          1.225 |
## 6102_U3_C18POS_48                                         -0.927 |
## 6102_U4_C18POS_50                                         -0.843 |
## 6103_U1_C18POS_21                                         -0.088 |
## 6103_U2_C18POS_60                                          1.566 |
Dist Dim.1 cos2 v.test Dim.2 cos2 v.test Dim.3 cos2 v.test
6101_U1_C18POS_59 | 24.673 | -9.190 0.139 -0.437 | -7.502 0.092 -0.515 | -9.728 0.155 -1.051 |
6101_U2_C18POS_30 | 31.022 | -7.697 0.062 -0.366 | -8.210 0.070 -0.563 | 8.542 0.076 0.923 |
6101_U3_C18POS_29_1 | 23.104 | -8.563 0.137 -0.407 | -6.971 0.091 -0.478 | -7.504 0.105 -0.810 |
6101_U4_C18POS_14 | 24.577 | -9.044 0.135 -0.430 | -6.798 0.077 -0.466 | -8.527 0.120 -0.921 |
6102_U1_C18POS_26_1 | 21.767 | -8.370 0.148 -0.398 | -6.285 0.083 -0.431 | -8.551 0.154 -0.923 |
6102_U2_C18POS_16 | 23.410 | -7.332 0.098 -0.349 | -6.343 0.073 -0.435 | 11.340 0.235 1.225 |
6102_U3_C18POS_48 | 33.928 | -7.323 0.047 -0.348 | -3.185 0.009 -0.219 | -8.579 0.064 -0.927 |
6102_U4_C18POS_50 | 23.082 | -7.190 0.097 -0.342 | -4.348 0.035 -0.298 | -7.807 0.114 -0.843 |
6103_U1_C18POS_21 | 29.267 | -2.553 0.008 -0.121 | -1.485 0.003 -0.102 | -0.811 0.001 -0.088 |
6103_U2_C18POS_60 | 31.321 | -7.237 0.053 -0.344 | -6.156 0.039 -0.422 | 14.503 0.214 1.566 |
# pull PC coordinates into df
PC_coord_noQCs_log2 <- as.data.frame(PCA.DC_imp_metabind_clust_log2_noQCs$ind$coord)

# bind back metadata from cols 1-10
PC_coord_noQCs_log2 <- bind_cols(anno_imp_metabind_clust_log2_noQCs[,1:11], PC_coord_noQCs_log2)

# grab some variance explained
importance_noQC <- PCA.DC_imp_metabind_clust_log2_noQCs$eig

# set variance explained with PC1, round to 2 digits
PC1_noQC <- round(importance_noQC[1,2], 2)

# set variance explained with PC2, round to 2 digits
PC2_noQC <- round(importance_noQC[2,2], 2)

Plots

Using FactoExtra

# scree plot
fviz_eig(PCA.DC_imp_metabind_clust_log2_noQCs)

# scores plot
fviz_pca_ind(PCA.DC_imp_metabind_clust_log2_noQCs)

# plot of contributions from features to PC1
(var_contrib_noQCs_PC1 <- fviz_contrib(PCA.DC_imp_metabind_clust_log2_noQCs,
             choice = "var",
             axes = 1,
             top = 25,
             title = "Var contribution to PC1: no QCs"))

# plot of contributions from features to PC2
(var_contrib_noQCs_PC2 <- fviz_contrib(PCA.DC_imp_metabind_clust_log2_noQCs,
             choice = "var",
             axes = 2,
             top = 25,
             title = "Var contribution to PC2: no QCs"))

Manual scores plots

Yellow vs red

(PCA_withoutQCs <- PC_coord_noQCs_log2 %>%
  ggplot(aes(x = Dim.1, 
             y = Dim.2,
             fill = Intervention)) +
    geom_point(shape = 21, alpha = 0.8) +
    geom_hline(yintercept = 0, linetype = "dashed", alpha=0.5) +
    geom_vline(xintercept = 0, linetype = "dashed", alpha=0.5) +
    scale_fill_manual(values = c("gold", "tomato1")) +
    scale_color_manual(values = "black") +  
    theme_minimal() +
    coord_fixed(PC2_noQC/PC1_noQC) +
    labs(x = glue::glue("PC1: {PC1_noQC}%"),
         y = glue::glue("PC2: {PC2_noQC}%"),
         fill = "Intervention",
         title = "Principal Components Analysis Scores Plot",
         subtitle = "Log2 transformed data, without QCs"))

ggplotly(PCA_withoutQCs)

pre vs post

(PCA_withoutQCs.pre_post <- PC_coord_noQCs_log2 %>%
  ggplot(aes(x = Dim.1, 
             y = Dim.2,
             fill = factor(pre_post_intervention, levels = c("pre_Yellow",
                                                             "post_Yellow",
                                                             "pre_Red",
                                                             "post_Red")),
             text = sample_ID)) +
    geom_point(shape = 21, alpha = 0.8) +
    geom_hline(yintercept = 0, linetype = "dashed", alpha=0.5) +
    geom_vline(xintercept = 0, linetype = "dashed", alpha=0.5) +
    scale_fill_manual(values = c("gray", "yellow1", "pink1", "red2")) +
    scale_color_manual(values = "black") +  
    theme_minimal() +
    coord_fixed(PC2_noQC/PC1_noQC) +
    labs(x = glue::glue("PC1: {PC1_noQC}%"),
         y = glue::glue("PC2: {PC2_noQC}%"),
         fill = "pre_post",
         title = "Principal Components Analysis Scores Plot",
         subtitle = "Log2 transformed, without QCs"))

ggplotly(PCA_withoutQCs.pre_post,
         tooltip = "text") 

From looking at the PCA plots, subject 6106 and 6112 are visual outliers. Let’s remove them.

Removal of outlier

With QCs

Wrangle

# go back to wide data
DC_imp_nooutliers_log2 <- anno_imp_metabind_clust_log2 %>%
  filter(Subject != 6106,
         Subject != 6112)

PCA.DC_imp_nooutliers_log2 <- PCA(DC_imp_nooutliers_log2,  # wide data
                                   quali.sup = 1:11, # remove qualitative variables
                                   graph = FALSE, # don't graph
                                   scale.unit = FALSE) # don't scale, already transformed data

# PCA summary
summary(PCA.DC_imp_nooutliers_log2)
## 
## Call:
## PCA(X = DC_imp_nooutliers_log2, scale.unit = FALSE, quali.sup = 1:11,  
##      graph = FALSE) 
## 
## 
## Eigenvalues
##                        Dim.1   Dim.2   Dim.3   Dim.4   Dim.5   Dim.6   Dim.7
## Variance             628.012  80.003  76.073  56.124  49.726  40.573  34.933
## % of var.             50.664   6.454   6.137   4.528   4.012   3.273   2.818
## Cumulative % of var.  50.664  57.119  63.256  67.783  71.795  75.068  77.886
##                        Dim.8   Dim.9  Dim.10  Dim.11  Dim.12  Dim.13  Dim.14
## Variance              27.643  26.037  24.397  18.719  17.907  12.987  12.775
## % of var.              2.230   2.101   1.968   1.510   1.445   1.048   1.031
## Cumulative % of var.  80.117  82.217  84.185  85.695  87.140  88.188  89.218
##                       Dim.15  Dim.16  Dim.17  Dim.18  Dim.19  Dim.20  Dim.21
## Variance              10.779  10.439   8.938   8.527   7.977   7.597   7.114
## % of var.              0.870   0.842   0.721   0.688   0.643   0.613   0.574
## Cumulative % of var.  90.088  90.930  91.651  92.339  92.982  93.595  94.169
##                       Dim.22  Dim.23  Dim.24  Dim.25  Dim.26  Dim.27  Dim.28
## Variance               6.444   5.977   5.503   5.196   5.152   4.836   4.582
## % of var.              0.520   0.482   0.444   0.419   0.416   0.390   0.370
## Cumulative % of var.  94.689  95.171  95.615  96.035  96.450  96.840  97.210
##                       Dim.29  Dim.30  Dim.31  Dim.32  Dim.33  Dim.34  Dim.35
## Variance               4.162   3.588   3.311   3.170   2.926   2.889   2.644
## % of var.              0.336   0.289   0.267   0.256   0.236   0.233   0.213
## Cumulative % of var.  97.546  97.835  98.102  98.358  98.594  98.827  99.040
##                       Dim.36  Dim.37  Dim.38  Dim.39  Dim.40  Dim.41  Dim.42
## Variance               2.452   2.321   2.064   2.012   1.763   0.395   0.230
## % of var.              0.198   0.187   0.167   0.162   0.142   0.032   0.019
## Cumulative % of var.  99.238  99.425  99.592  99.754  99.896  99.928  99.947
##                       Dim.43  Dim.44  Dim.45  Dim.46  Dim.47
## Variance               0.210   0.187   0.174   0.088   0.000
## % of var.              0.017   0.015   0.014   0.007   0.000
## Cumulative % of var.  99.964  99.979  99.993 100.000 100.000
## 
## Individuals (the 10 first)
##                                                                Dist     Dim.1
## 1                                                         |  27.391 | -17.588
## 2                                                         |  25.234 | -17.617
## 3                                                         |  29.723 |  -6.298
## 4                                                         |  26.846 | -16.311
## 5                                                         |  27.493 | -14.359
## 6                                                         |  30.688 | -14.378
## 7                                                         |  25.533 | -11.501
## 8                                                         |  23.059 |  -9.879
## 9                                                         |  30.043 | -10.063
## 10                                                        |  25.813 |  -9.788
##                                                               ctr    cos2  
## 1                                                           1.026   0.412 |
## 2                                                           1.030   0.487 |
## 3                                                           0.132   0.045 |
## 4                                                           0.883   0.369 |
## 5                                                           0.684   0.273 |
## 6                                                           0.686   0.219 |
## 7                                                           0.439   0.203 |
## 8                                                           0.324   0.184 |
## 9                                                           0.336   0.112 |
## 10                                                          0.318   0.144 |
##                                                             Dim.2     ctr
## 1                                                           4.065   0.430
## 2                                                           2.005   0.105
## 3                                                          -9.076   2.145
## 4                                                          -0.254   0.002
## 5                                                          -0.246   0.002
## 6                                                          11.126   3.224
## 7                                                          -2.691   0.189
## 8                                                          -4.698   0.575
## 9                                                          -0.348   0.003
## 10                                                         -1.289   0.043
##                                                              cos2     Dim.3
## 1                                                           0.022 |   6.867
## 2                                                           0.006 |   6.771
## 3                                                           0.093 |   6.240
## 4                                                           0.000 |   7.255
## 5                                                           0.000 |   4.425
## 6                                                           0.131 |   4.961
## 7                                                           0.011 |   5.715
## 8                                                           0.042 |  -4.735
## 9                                                           0.000 |   9.683
## 10                                                          0.002 |   4.413
##                                                               ctr    cos2  
## 1                                                           1.291   0.063 |
## 2                                                           1.255   0.072 |
## 3                                                           1.066   0.044 |
## 4                                                           1.441   0.073 |
## 5                                                           0.536   0.026 |
## 6                                                           0.674   0.026 |
## 7                                                           0.894   0.050 |
## 8                                                           0.614   0.042 |
## 9                                                           2.567   0.104 |
## 10                                                          0.533   0.029 |
## 
## Variables (the 10 first)
##                                                              Dim.1    ctr
## 226.9516_0.553                                            |  0.018  0.000
## 159.1492_0.608                                            | -0.630  0.063
## 175.1442_0.616                                            |  0.098  0.002
## 189.1684_0.616                                            | -0.010  0.000
## 189.16_0.615                                              | -0.012  0.000
## 156.0769_0.621                                            |  0.016  0.000
## 170.0926_0.62                                             |  0.016  0.000
## 136.0482_0.633                                            |  0.016  0.000
## 137.071_0.636                                             |  0.071  0.001
## 162.1126_0.642                                            |  0.160  0.004
##                                                             cos2    Dim.2
## 226.9516_0.553                                             0.001 |  0.002
## 159.1492_0.608                                             0.468 |  0.219
## 175.1442_0.616                                             0.016 |  0.271
## 189.1684_0.616                                             0.000 |  0.157
## 189.16_0.615                                               0.001 |  0.015
## 156.0769_0.621                                             0.000 |  0.030
## 170.0926_0.62                                              0.000 |  0.291
## 136.0482_0.633                                             0.001 | -0.017
## 137.071_0.636                                              0.019 |  0.078
## 162.1126_0.642                                             0.029 |  0.196
##                                                              ctr   cos2  
## 226.9516_0.553                                             0.000  0.000 |
## 159.1492_0.608                                             0.060  0.057 |
## 175.1442_0.616                                             0.092  0.125 |
## 189.1684_0.616                                             0.031  0.062 |
## 189.16_0.615                                               0.000  0.001 |
## 156.0769_0.621                                             0.001  0.001 |
## 170.0926_0.62                                              0.106  0.112 |
## 136.0482_0.633                                             0.000  0.001 |
## 137.071_0.636                                              0.008  0.023 |
## 162.1126_0.642                                             0.048  0.044 |
##                                                            Dim.3    ctr   cos2
## 226.9516_0.553                                             0.023  0.001  0.002
## 159.1492_0.608                                            -0.008  0.000  0.000
## 175.1442_0.616                                            -0.103  0.014  0.018
## 189.1684_0.616                                            -0.194  0.050  0.095
## 189.16_0.615                                               0.009  0.000  0.000
## 156.0769_0.621                                             0.067  0.006  0.006
## 170.0926_0.62                                             -0.194  0.050  0.050
## 136.0482_0.633                                             0.057  0.004  0.007
## 137.071_0.636                                             -0.084  0.009  0.027
## 162.1126_0.642                                             0.085  0.009  0.008
##                                                            
## 226.9516_0.553                                            |
## 159.1492_0.608                                            |
## 175.1442_0.616                                            |
## 189.1684_0.616                                            |
## 189.16_0.615                                              |
## 156.0769_0.621                                            |
## 170.0926_0.62                                             |
## 136.0482_0.633                                            |
## 137.071_0.636                                             |
## 162.1126_0.642                                            |
## 
## Supplementary categories (the 10 first)
##                                                                Dist     Dim.1
## sample_ID_6101_U1_C18POS_59                               |  27.391 | -17.588
## sample_ID_6101_U2_C18POS_30                               |  31.486 | -11.643
## sample_ID_6101_U3_C18POS_29_1                             |  25.769 | -16.428
## sample_ID_6101_U4_C18POS_14                               |  26.832 | -16.086
## sample_ID_6102_U1_C18POS_26_1                             |  25.234 | -17.617
## sample_ID_6102_U2_C18POS_16                               |  24.321 | -11.377
## sample_ID_6102_U3_C18POS_48                               |  33.883 |  -8.330
## sample_ID_6102_U4_C18POS_50                               |  24.519 | -12.113
## sample_ID_6103_U1_C18POS_21                               |  29.723 |  -6.298
## sample_ID_6103_U2_C18POS_60                               |  31.457 |  -9.662
##                                                              cos2  v.test  
## sample_ID_6101_U1_C18POS_59                                 0.412  -0.702 |
## sample_ID_6101_U2_C18POS_30                                 0.137  -0.465 |
## sample_ID_6101_U3_C18POS_29_1                               0.406  -0.656 |
## sample_ID_6101_U4_C18POS_14                                 0.359  -0.642 |
## sample_ID_6102_U1_C18POS_26_1                               0.487  -0.703 |
## sample_ID_6102_U2_C18POS_16                                 0.219  -0.454 |
## sample_ID_6102_U3_C18POS_48                                 0.060  -0.332 |
## sample_ID_6102_U4_C18POS_50                                 0.244  -0.483 |
## sample_ID_6103_U1_C18POS_21                                 0.045  -0.251 |
## sample_ID_6103_U2_C18POS_60                                 0.094  -0.386 |
##                                                             Dim.2    cos2
## sample_ID_6101_U1_C18POS_59                                 4.065   0.022
## sample_ID_6101_U2_C18POS_30                                -0.871   0.001
## sample_ID_6101_U3_C18POS_29_1                               2.637   0.010
## sample_ID_6101_U4_C18POS_14                                 0.501   0.000
## sample_ID_6102_U1_C18POS_26_1                               2.005   0.006
## sample_ID_6102_U2_C18POS_16                                -2.726   0.013
## sample_ID_6102_U3_C18POS_48                                 2.023   0.004
## sample_ID_6102_U4_C18POS_50                                -0.591   0.001
## sample_ID_6103_U1_C18POS_21                                -9.076   0.093
## sample_ID_6103_U2_C18POS_60                               -12.027   0.146
##                                                            v.test     Dim.3
## sample_ID_6101_U1_C18POS_59                                 0.454 |   6.867
## sample_ID_6101_U2_C18POS_30                                -0.097 |  -9.024
## sample_ID_6101_U3_C18POS_29_1                               0.295 |   5.131
## sample_ID_6101_U4_C18POS_14                                 0.056 |   7.761
## sample_ID_6102_U1_C18POS_26_1                               0.224 |   6.771
## sample_ID_6102_U2_C18POS_16                                -0.305 | -10.800
## sample_ID_6102_U3_C18POS_48                                 0.226 |   8.833
## sample_ID_6102_U4_C18POS_50                                -0.066 |   8.896
## sample_ID_6103_U1_C18POS_21                                -1.015 |   6.240
## sample_ID_6103_U2_C18POS_60                                -1.345 |  -9.620
##                                                              cos2  v.test  
## sample_ID_6101_U1_C18POS_59                                 0.063   0.787 |
## sample_ID_6101_U2_C18POS_30                                 0.082  -1.035 |
## sample_ID_6101_U3_C18POS_29_1                               0.040   0.588 |
## sample_ID_6101_U4_C18POS_14                                 0.084   0.890 |
## sample_ID_6102_U1_C18POS_26_1                               0.072   0.776 |
## sample_ID_6102_U2_C18POS_16                                 0.197  -1.238 |
## sample_ID_6102_U3_C18POS_48                                 0.068   1.013 |
## sample_ID_6102_U4_C18POS_50                                 0.132   1.020 |
## sample_ID_6103_U1_C18POS_21                                 0.044   0.715 |
## sample_ID_6103_U2_C18POS_60                                 0.094  -1.103 |
# pull PC coordinates into df
PC_nooutliers_QC_log2 <- as.data.frame(PCA.DC_imp_nooutliers_log2$ind$coord)

# bind back metadata from cols 1-11
PC_nooutliers_QC_log2 <- bind_cols(DC_imp_nooutliers_log2[,1:11], PC_nooutliers_QC_log2)

# grab some variance explained
importance_nooutliers_QC <- PCA.DC_imp_nooutliers_log2$eig

# set variance explained with PC1, round to 2 digits
PC1_nooutliers_withQC <- round(importance_nooutliers_QC[1,2], 2)

# set variance explained with PC2, round to 2 digits
PC2_nooutliers_withQC <- round(importance_nooutliers_QC[2,2], 2)

Plots

Using FactoExtra package

# scree plot
fviz_eig(PCA.DC_imp_nooutliers_log2)

# scores plot
fviz_pca_ind(PCA.DC_imp_nooutliers_log2)

Manual scores plots

##### Red vs yellow

# manual scores plot
(PCA_nooutliers_withQCs <- PC_nooutliers_QC_log2 %>%
  ggplot(aes(x = Dim.1, y = Dim.2,
             fill = factor(Intervention, levels = c("Yellow", "Red", "QC")))) +
  geom_point(shape = 21, alpha = 0.8) +
  scale_fill_manual(values = c("gold", "tomato1", "light grey")) +
  scale_color_manual(values = "black") +  
  theme_minimal() +
  labs(x = glue::glue("PC1: {PC1_nooutliers_withQC}%"),
       y = glue::glue("PC2: {PC2_nooutliers_withQC}%"),
       fill = "Group",
       title = "Principal Components Analysis Scores Plot"))

Pre vs post
(PCA_nooutliers_prepost_withQCs <- PC_nooutliers_QC_log2 %>%
  ggplot(aes(x = Dim.1, 
             y = Dim.2,
             fill = factor(pre_post_intervention, levels = c("pre_Yellow",
                                                             "post_Yellow",
                                                             "pre_Red",
                                                             "post_Red")),
             text = sample_ID)) +
    geom_point(shape = 21, alpha = 0.8) +
    geom_hline(yintercept = 0, linetype = "dashed", alpha=0.5) +
    geom_vline(xintercept = 0, linetype = "dashed", alpha=0.5) +
    scale_fill_manual(values = c("gray", "yellow1", "pink1", "red2")) +
    scale_color_manual(values = "black") +  
    theme_minimal() +
    labs(x = glue::glue("PC1: {PC1_nooutliers_withQC}%"),
         y = glue::glue("PC2: {PC2_nooutliers_withQC}%"),
         fill = "pre_post",
         title = "Principal Components Analysis Scores Plot"))

ggplotly(PCA_nooutliers_prepost_withQCs,
         tooltip = "text") 

Without QCs

Wrangle

imp_nooutliers_noQCs_log2 <- DC_imp_nooutliers_log2 %>%
  filter(Intervention != "QC") 

PCA.imp_nooutliers_noQCs_log2 <- PCA(imp_nooutliers_noQCs_log2, # wide data
                               quali.sup=1:11, # remove qualitative variables
                               graph=FALSE, # don't graph
                               scale.unit=FALSE) # don't scale, we already did this

# look at summary
kable(summary(PCA.imp_nooutliers_noQCs_log2))
## 
## Call:
## PCA(X = imp_nooutliers_noQCs_log2, scale.unit = FALSE, quali.sup = 1:11,  
##      graph = FALSE) 
## 
## 
## Eigenvalues
##                        Dim.1   Dim.2   Dim.3   Dim.4   Dim.5   Dim.6   Dim.7
## Variance              96.261  93.644  67.815  61.286  51.306  44.034  33.471
## % of var.             12.866  12.516   9.064   8.191   6.857   5.885   4.474
## Cumulative % of var.  12.866  25.382  34.446  42.637  49.495  55.380  59.854
##                        Dim.8   Dim.9  Dim.10  Dim.11  Dim.12  Dim.13  Dim.14
## Variance              31.911  29.752  22.786  21.924  17.835  15.445  13.502
## % of var.              4.265   3.977   3.046   2.930   2.384   2.064   1.805
## Cumulative % of var.  64.119  68.096  71.141  74.071  76.455  78.520  80.324
##                       Dim.15  Dim.16  Dim.17  Dim.18  Dim.19  Dim.20  Dim.21
## Variance              12.614  10.861  10.236   9.571   9.324   8.759   7.869
## % of var.              1.686   1.452   1.368   1.279   1.246   1.171   1.052
## Cumulative % of var.  82.010  83.462  84.830  86.109  87.355  88.526  89.578
##                       Dim.22  Dim.23  Dim.24  Dim.25  Dim.26  Dim.27  Dim.28
## Variance               7.213   6.699   6.235   6.198   5.803   5.513   5.094
## % of var.              0.964   0.895   0.833   0.828   0.776   0.737   0.681
## Cumulative % of var.  90.542  91.437  92.271  93.099  93.875  94.612  95.293
##                       Dim.29  Dim.30  Dim.31  Dim.32  Dim.33  Dim.34  Dim.35
## Variance               4.361   3.973   3.855   3.538   3.508   3.182   2.942
## % of var.              0.583   0.531   0.515   0.473   0.469   0.425   0.393
## Cumulative % of var.  95.875  96.406  96.922  97.395  97.863  98.289  98.682
##                       Dim.36  Dim.37  Dim.38  Dim.39
## Variance               2.810   2.480   2.416   2.156
## % of var.              0.376   0.331   0.323   0.288
## Cumulative % of var.  99.058  99.389  99.712 100.000
## 
## Individuals (the 10 first)
##                                                               Dist    Dim.1
## 1                                                         | 22.177 |  1.491
## 2                                                         | 19.368 | -0.355
## 3                                                         | 29.393 | -9.461
## 4                                                         | 22.105 | -2.507
## 5                                                         | 23.759 | -1.703
## 6                                                         | 27.369 |  9.306
## 7                                                         | 22.789 | -3.784
## 8                                                         | 20.866 | -3.634
## 9                                                         | 28.364 | -2.372
## 10                                                        | 23.978 | -2.290
##                                                              ctr   cos2  
## 1                                                          0.058  0.005 |
## 2                                                          0.003  0.000 |
## 3                                                          2.325  0.104 |
## 4                                                          0.163  0.013 |
## 5                                                          0.075  0.005 |
## 6                                                          2.249  0.116 |
## 7                                                          0.372  0.028 |
## 8                                                          0.343  0.030 |
## 9                                                          0.146  0.007 |
## 10                                                         0.136  0.009 |
##                                                            Dim.2    ctr   cos2
## 1                                                         -9.589  2.455  0.187
## 2                                                         -8.720  2.030  0.203
## 3                                                         -2.323  0.144  0.006
## 4                                                         -8.338  1.856  0.142
## 5                                                         -5.259  0.738  0.049
## 6                                                         -8.210  1.799  0.090
## 7                                                         -4.671  0.583  0.042
## 8                                                          5.419  0.784  0.067
## 9                                                         -9.050  2.187  0.102
## 10                                                        -4.105  0.450  0.029
##                                                              Dim.3    ctr
## 1                                                         | -4.758  0.835
## 2                                                         | -4.139  0.632
## 3                                                         |  1.185  0.052
## 4                                                         | -2.817  0.293
## 5                                                         | -1.906  0.134
## 6                                                         |  2.124  0.166
## 7                                                         |  2.880  0.306
## 8                                                         | -2.610  0.251
## 9                                                         |  4.774  0.840
## 10                                                        | -4.969  0.910
##                                                             cos2  
## 1                                                          0.046 |
## 2                                                          0.046 |
## 3                                                          0.002 |
## 4                                                          0.016 |
## 5                                                          0.006 |
## 6                                                          0.006 |
## 7                                                          0.016 |
## 8                                                          0.016 |
## 9                                                          0.028 |
## 10                                                         0.043 |
## 
## Variables (the 10 first)
##                                                              Dim.1    ctr
## 226.9516_0.553                                            | -0.013  0.000
## 159.1492_0.608                                            |  0.218  0.049
## 175.1442_0.616                                            |  0.318  0.105
## 189.1684_0.616                                            |  0.210  0.046
## 189.16_0.615                                              |  0.001  0.000
## 156.0769_0.621                                            | -0.004  0.000
## 170.0926_0.62                                             |  0.335  0.117
## 136.0482_0.633                                            | -0.035  0.001
## 137.071_0.636                                             |  0.101  0.011
## 162.1126_0.642                                            |  0.193  0.039
##                                                             cos2    Dim.2
## 226.9516_0.553                                             0.001 | -0.048
## 159.1492_0.608                                             0.091 | -0.081
## 175.1442_0.616                                             0.146 |  0.050
## 189.1684_0.616                                             0.092 |  0.157
## 189.16_0.615                                               0.000 | -0.043
## 156.0769_0.621                                             0.000 | -0.123
## 170.0926_0.62                                              0.125 |  0.084
## 136.0482_0.633                                             0.002 | -0.062
## 137.071_0.636                                              0.033 |  0.064
## 162.1126_0.642                                             0.037 | -0.129
##                                                              ctr   cos2  
## 226.9516_0.553                                             0.002  0.008 |
## 159.1492_0.608                                             0.007  0.013 |
## 175.1442_0.616                                             0.003  0.004 |
## 189.1684_0.616                                             0.026  0.052 |
## 189.16_0.615                                               0.002  0.005 |
## 156.0769_0.621                                             0.016  0.017 |
## 170.0926_0.62                                              0.008  0.008 |
## 136.0482_0.633                                             0.004  0.007 |
## 137.071_0.636                                              0.004  0.013 |
## 162.1126_0.642                                             0.018  0.016 |
##                                                            Dim.3    ctr   cos2
## 226.9516_0.553                                            -0.312  0.143  0.341
## 159.1492_0.608                                             0.222  0.073  0.094
## 175.1442_0.616                                             0.163  0.039  0.038
## 189.1684_0.616                                             0.088  0.012  0.016
## 189.16_0.615                                              -0.069  0.007  0.014
## 156.0769_0.621                                             0.063  0.006  0.004
## 170.0926_0.62                                             -0.207  0.063  0.048
## 136.0482_0.633                                            -0.339  0.169  0.197
## 137.071_0.636                                             -0.102  0.015  0.034
## 162.1126_0.642                                             0.124  0.023  0.015
##                                                            
## 226.9516_0.553                                            |
## 159.1492_0.608                                            |
## 175.1442_0.616                                            |
## 189.1684_0.616                                            |
## 189.16_0.615                                              |
## 156.0769_0.621                                            |
## 170.0926_0.62                                             |
## 136.0482_0.633                                            |
## 137.071_0.636                                             |
## 162.1126_0.642                                            |
## 
## Supplementary categories (the 10 first)
##                                                               Dist    Dim.1
## 6101_U1_C18POS_59                                         | 22.177 |  1.491
## 6101_U2_C18POS_30                                         | 29.285 |  0.688
## 6101_U3_C18POS_29_1                                       | 20.734 |  0.603
## 6101_U4_C18POS_14                                         | 22.205 | -1.904
## 6102_U1_C18POS_26_1                                       | 19.368 | -0.355
## 6102_U2_C18POS_16                                         | 21.448 | -0.518
## 6102_U3_C18POS_48                                         | 32.995 |  0.188
## 6102_U4_C18POS_50                                         | 21.415 | -2.611
## 6103_U1_C18POS_21                                         | 29.393 | -9.461
## 6103_U2_C18POS_60                                         | 29.874 | -9.327
##                                                             cos2 v.test  
## 6101_U1_C18POS_59                                          0.005  0.152 |
## 6101_U2_C18POS_30                                          0.001  0.070 |
## 6101_U3_C18POS_29_1                                        0.001  0.061 |
## 6101_U4_C18POS_14                                          0.007 -0.194 |
## 6102_U1_C18POS_26_1                                        0.000 -0.036 |
## 6102_U2_C18POS_16                                          0.001 -0.053 |
## 6102_U3_C18POS_48                                          0.000  0.019 |
## 6102_U4_C18POS_50                                          0.015 -0.266 |
## 6103_U1_C18POS_21                                          0.104 -0.964 |
## 6103_U2_C18POS_60                                          0.097 -0.951 |
##                                                            Dim.2   cos2 v.test
## 6101_U1_C18POS_59                                         -9.589  0.187 -0.991
## 6101_U2_C18POS_30                                          7.942  0.074  0.821
## 6101_U3_C18POS_29_1                                       -7.336  0.125 -0.758
## 6101_U4_C18POS_14                                         -9.051  0.166 -0.935
## 6102_U1_C18POS_26_1                                       -8.720  0.203 -0.901
## 6102_U2_C18POS_16                                         10.544  0.242  1.090
## 6102_U3_C18POS_48                                         -8.643  0.069 -0.893
## 6102_U4_C18POS_50                                         -8.582  0.161 -0.887
## 6103_U1_C18POS_21                                         -2.323  0.006 -0.240
## 6103_U2_C18POS_60                                         12.634  0.179  1.306
##                                                              Dim.3   cos2
## 6101_U1_C18POS_59                                         | -4.758  0.046
## 6101_U2_C18POS_30                                         |  4.097  0.020
## 6101_U3_C18POS_29_1                                       | -6.740  0.106
## 6101_U4_C18POS_14                                         | -1.348  0.004
## 6102_U1_C18POS_26_1                                       | -4.139  0.046
## 6102_U2_C18POS_16                                         |  7.046  0.108
## 6102_U3_C18POS_48                                         |  2.545  0.006
## 6102_U4_C18POS_50                                         |  7.651  0.128
## 6103_U1_C18POS_21                                         |  1.185  0.002
## 6103_U2_C18POS_60                                         |  7.989  0.072
##                                                           v.test  
## 6101_U1_C18POS_59                                         -0.578 |
## 6101_U2_C18POS_30                                          0.497 |
## 6101_U3_C18POS_29_1                                       -0.818 |
## 6101_U4_C18POS_14                                         -0.164 |
## 6102_U1_C18POS_26_1                                       -0.503 |
## 6102_U2_C18POS_16                                          0.856 |
## 6102_U3_C18POS_48                                          0.309 |
## 6102_U4_C18POS_50                                          0.929 |
## 6103_U1_C18POS_21                                          0.144 |
## 6103_U2_C18POS_60                                          0.970 |
Dist Dim.1 cos2 v.test Dim.2 cos2 v.test Dim.3 cos2 v.test
6101_U1_C18POS_59 | 22.177 | 1.491 0.005 0.152 | -9.589 0.187 -0.991 | -4.758 0.046 -0.578 |
6101_U2_C18POS_30 | 29.285 | 0.688 0.001 0.070 | 7.942 0.074 0.821 | 4.097 0.020 0.497 |
6101_U3_C18POS_29_1 | 20.734 | 0.603 0.001 0.061 | -7.336 0.125 -0.758 | -6.740 0.106 -0.818 |
6101_U4_C18POS_14 | 22.205 | -1.904 0.007 -0.194 | -9.051 0.166 -0.935 | -1.348 0.004 -0.164 |
6102_U1_C18POS_26_1 | 19.368 | -0.355 0.000 -0.036 | -8.720 0.203 -0.901 | -4.139 0.046 -0.503 |
6102_U2_C18POS_16 | 21.448 | -0.518 0.001 -0.053 | 10.544 0.242 1.090 | 7.046 0.108 0.856 |
6102_U3_C18POS_48 | 32.995 | 0.188 0.000 0.019 | -8.643 0.069 -0.893 | 2.545 0.006 0.309 |
6102_U4_C18POS_50 | 21.415 | -2.611 0.015 -0.266 | -8.582 0.161 -0.887 | 7.651 0.128 0.929 |
6103_U1_C18POS_21 | 29.393 | -9.461 0.104 -0.964 | -2.323 0.006 -0.240 | 1.185 0.002 0.144 |
6103_U2_C18POS_60 | 29.874 | -9.327 0.097 -0.951 | 12.634 0.179 1.306 | 7.989 0.072 0.970 |
# pull PC coordinates into df
PC_coord_nooutliers_noQC_log2 <- as.data.frame(PCA.imp_nooutliers_noQCs_log2$ind$coord)

# bind back metadata from cols 1-11
PC_coord_nooutliers_noQC_log2 <- bind_cols(imp_nooutliers_noQCs_log2[,1:11], PC_coord_nooutliers_noQC_log2)

# grab some variance explained
importance_nooutliers_noQC <- PCA.imp_nooutliers_noQCs_log2$eig

# set variance explained with PC1, round to 2 digits
PC1_nooutliers_noQC <- round(importance_nooutliers_noQC[1,2], 2)

# set variance explained with PC2, round to 2 digits
PC2_nooutliers_noQC <- round(importance_nooutliers_noQC[2,2], 2)

Plots

Using FactoExtra

# scree plot
fviz_eig(PCA.imp_nooutliers_noQCs_log2)

# scores plot
fviz_pca_ind(PCA.imp_nooutliers_noQCs_log2)

# plot of contributions from features to PC1
(var_contrib_nooutliers_noQCs_PC1 <- fviz_contrib(PCA.imp_nooutliers_noQCs_log2,
             choice = "var",
             axes = 1,
             top = 20,
             title = "Var contribution to PC1: no outliers, no QCs"))

# plot of contributions from features to PC2
(var_contrib_nooutliers_noQCs_PC2 <- fviz_contrib(PCA.imp_nooutliers_noQCs_log2,
             choice = "var",
             axes = 2,
             top = 20,
             title = "Var contribution to PC2: no outliers, no QCs"))

Manual scores plots

Red vs yellow
(PCA_nooutliers_withoutQCs <- PC_coord_nooutliers_noQC_log2 %>%
  ggplot(aes(x = Dim.1, 
             y = Dim.2,
             fill = Intervention)) +
    geom_point(shape = 21, alpha = 0.8) +
    geom_hline(yintercept = 0, linetype = "dashed", alpha=0.5) +
    geom_vline(xintercept = 0, linetype = "dashed", alpha=0.5) +
    scale_fill_manual(values = c("tomato1", "gold")) +
    scale_color_manual(values = "black") +  
    theme_minimal() +
    coord_fixed(PC2_nooutliers_noQC/PC1_nooutliers_noQC) +
    labs(x = glue::glue("PC1: {PC1_nooutliers_noQC}%"),
         y = glue::glue("PC2: {PC2_nooutliers_noQC}%"),
         fill = "Intervention",
         title = "Principal Components Analysis Scores Plot"))

ggplotly(PCA_nooutliers_withoutQCs)
Pre vs post
(PCA_nooutliers_noQCs.prepost <- PC_coord_nooutliers_noQC_log2 %>%
  ggplot(aes(x = Dim.1, 
             y = Dim.2,
             fill = factor(pre_post_intervention, levels = c("pre_Yellow",
                                                             "post_Yellow",
                                                             "pre_Red",
                                                             "post_Red")),
             text = sample_ID)) +
    geom_point(shape = 21, alpha = 0.8) +
    geom_hline(yintercept = 0, linetype = "dashed", alpha=0.5) +
    geom_vline(xintercept = 0, linetype = "dashed", alpha=0.5) +
    scale_fill_manual(values = c("gray", "yellow1", "pink1", "red2")) +
    scale_color_manual(values = "black") +  
    theme_minimal() +
    coord_fixed(PC2_nooutliers_noQC/PC1_nooutliers_noQC) +
    labs(x = glue::glue("PC1: {PC1_nooutliers_noQC}%"),
         y = glue::glue("PC2: {PC2_nooutliers_noQC}%"),
         fill = "pre_post",
         title = "Principal Components Analysis Scores Plot",
         subtitle = "Log2 transformed data, no outliers"))

ggplotly(PCA_nooutliers_noQCs.prepost,
         tooltip = "text") 
M v F
(PCA_nooutliers_noQCs.MvsF <- PC_coord_nooutliers_noQC_log2 %>%
  ggplot(aes(x = Dim.1, 
             y = Dim.2,
             fill = factor(Sex, levels = c("M","F")),
             text = sample_ID)) +
    geom_point(shape = 21, alpha = 0.8) +
    geom_hline(yintercept = 0, linetype = "dashed", alpha=0.5) +
    geom_vline(xintercept = 0, linetype = "dashed", alpha=0.5) +
    scale_fill_manual(values = c("green", "pink")) +
    scale_color_manual(values = "black") +  
    theme_minimal() +
    coord_fixed(PC2_nooutliers_noQC/PC1_nooutliers_noQC) +
    labs(x = glue::glue("PC1: {PC1_nooutliers_noQC}%"),
         y = glue::glue("PC2: {PC2_nooutliers_noQC}%"),
         fill = "pre_post",
         title = "Principal Components Analysis Scores Plot",
         subtitle = "Log2 transformed data, no 6106"))

ggplotly(PCA_nooutliers_noQCs.MvsF,
         tooltip = "text")

PCAtools pckg

W/ Outliers

Data wrangling

# create rel abund df suitable for PCAtools package
imp_clust_omicsdata_outliers_forPCAtools <- as.data.frame(t(anno_imp_metabind_clust_log2[,-c(2:11)])) # transpose df (using df with key)

names(imp_clust_omicsdata_outliers_forPCAtools) <- imp_clust_omicsdata_outliers_forPCAtools[1,] # make sample IDs column names

imp_clust_omicsdata_outliers_forPCAtools <- imp_clust_omicsdata_outliers_forPCAtools[-1,] # remove sample ID row

# create metadata df suitable for PCAtools pckg
metadata_outliers_forPCAtools <- metadata %>%
  column_to_rownames(var = "sample_ID") # change sample ID column to rownames

# create a vector so that col names in abundance df matches metadata df
order_outliers_forPCAtools <- match(rownames(metadata_outliers_forPCAtools), colnames(imp_clust_omicsdata_outliers_forPCAtools))

# reorder col names in abundance df so that it matches metadata
abundata_outliers_reordered_forPCAtools <- imp_clust_omicsdata_outliers_forPCAtools[ ,order_outliers_forPCAtools] 

# change abundance df to numeric and change name to for consistency! (using df that is already log2 transformed as of 8/26/24)
log2_abundata_outliers_reordered_forPCAtools <-
  abundata_outliers_reordered_forPCAtools %>%
  mutate_all(as.numeric)


# unite pre_post column with intervention column to create pre_intervention column
metadata_outliers_forPCAtools <- metadata_outliers_forPCAtools %>%
  unite(col = "pre_post_intervention",
        c("pre_post","Intervention"),
        sep = "_",
        remove = FALSE)

PCA

# pca
p_outliers <- PCAtools::pca(log2_abundata_outliers_reordered_forPCAtools, 
         metadata = metadata_outliers_forPCAtools, 
         scale = FALSE # using scaled data already (log2 transformed)
         
)

More PCAs

Pre vs post both

PC1vPC2
(PCAtools_outliers <- biplot(p_outliers,
                               lab = paste0(metadata_outliers_forPCAtools$Subject),
                           colby = 'pre_post_intervention',
                           colkey = c("pre_Yellow" = "lemonchiffon1",
                                        "post_Yellow" = "yellow2",
                                        "pre_Red" = "rosybrown2",
                                        "post_Red" = "darkred"),
                           hline = 0, vline = 0,
                           legendPosition = 'right',
                           title = "PCA Scores Plot with Loadings",
                           subtitle = "Log2 transformed data, c18 (+), without QCs but with outliers /n99% Confidence Ellipses",
                           ellipse = TRUE,
                           ellipseType = 't', # assumes multivariate
                           ellipseLevel = 0.99,
                           ellipseFill = TRUE,
                           ellipseAlpha = 0.2,
                           ellipseLineSize = 0.5,
                           xlim = c(-10, 10),
                           ylim = c(-10, 10),
                           showLoadings = FALSE))

6106 and 6112 are outside of the 99% confidence interval, we will classify them as true outliers moving forward.

No outliers

Data wrangling

# create rel abund df suitable for PCAtools package

imp_clust_omicsdata_forPCAtools <- as.data.frame(t(anno_imp_metabind_clust_log2[,-c(2:11)])) # transpose df 

names(imp_clust_omicsdata_forPCAtools) <- imp_clust_omicsdata_forPCAtools[1,] # make sample IDs column names

imp_clust_omicsdata_forPCAtools <- imp_clust_omicsdata_forPCAtools[-1,] # remove sample ID row

imp_clust_omicsdata_forPCAtools <- imp_clust_omicsdata_forPCAtools %>%
  dplyr::select(!contains("QC")) # remove QC observations


# create metadata df suitable for PCAtools pckg
metadata_forPCAtools <- metadata %>%
  column_to_rownames(var = "sample_ID") # change sample ID column to rownames

# create a vector so that col names in abundance df matches metadata df
order_forPCAtools <- match(rownames(metadata_forPCAtools), colnames(imp_clust_omicsdata_forPCAtools))

# reorder col names in abundance df so that it matches metadata
abundata_reordered_forPCAtools <- imp_clust_omicsdata_forPCAtools[ ,order_forPCAtools] 

# change abundance df to numeric
log2_abundata_reordered_forPCAtools <- abundata_reordered_forPCAtools %>%
  mutate_at(1:ncol(.), as.numeric)

# fix rownames to have keys again
rownames(log2_abundata_reordered_forPCAtools) <- rownames(abundata_reordered_forPCAtools)

# remove outlier subj from both df
log2_abundata_forPCAtools <- log2_abundata_reordered_forPCAtools %>%
  dplyr::select(!contains("6106")) %>%
  dplyr::select(!contains("6112"))

metadata_forPCAtools <- metadata_forPCAtools %>%
  filter(Subject != 6106,
         Subject != 6112)

# unite pre_post column with intervention column to create pre_intervention column
metadata_forPCAtools <- metadata_forPCAtools %>%
  unite(col = "pre_post_intervention",
        c("pre_post","Intervention"),
        sep = "_",
        remove = FALSE)

Screeplot analysis

Horn’s parallel analysis

horn <- parallelPCA(log2_abundata_forPCAtools)

horn$n
## [1] 9
# pca
p <- PCAtools::pca(log2_abundata_forPCAtools, 
         metadata = metadata_forPCAtools, 
         scale = FALSE # using scaled data already (log2 transformed)
         
)

Elbow method

elbow <- findElbowPoint(p$variance)

elbow
## PC5 
##   5
  screeplot(p,
    components = getComponents(p, 1:20),
    vline = c(horn$n, elbow)) +
  geom_label(aes(x = horn$n + 1, y = 50,
      label = 'Horn\'s', vjust = -1, size = 8)) +
    geom_label(aes(x = elbow + 1, y = 50,
      label = 'Elbow method', vjust = -3, size = 8))

How many PCs do we need to capture at least 80% variance?

which(cumsum(p$variance) > 80)[1]
## PC14 
##   14

More PCAs

Pre vs post both

PC1vPC2
biplot(p,
       lab = paste0(metadata_forPCAtools$Subject),
          colby = 'pre_post_intervention',
          colkey = c("pre_Yellow" = "lemonchiffon1",
                                        "post_Yellow" = "yellow2",
                                        "pre_Red" = "rosybrown2",
                                        "post_Red" = "darkred"),
         colLegendTitle = "Intervention Timepoint",
         # ellipse config
         ellipse = TRUE,
         ellipseType = 't',
         ellipseLevel = 0.99,
         ellipseFill = TRUE,
         ellipseAlpha = 0.2,
         ellipseLineSize = 1.0,
         xlim = c(-10,10), ylim = c(-10, 10),
         hline = 0, vline = 0,
       legendPosition = 'right',
       title = "PCA Scores Plot",
       subtitle = "Log2 transformed data, c18 (+), outliers 6106 and 6112 removed, no QCs \n99% confidence level ellipses")

(PCA.colby.prevspost <- biplot(p,
                               lab = NULL,
                           colby = 'pre_post_intervention',
                           colkey = c("pre_Yellow" = "lemonchiffon1",
                                        "post_Yellow" = "yellow2",
                                        "pre_Red" = "rosybrown2",
                                        "post_Red" = "darkred"),
                           hline = 0, vline = 0,
         legendPosition = 'right',
         title = "PCA Scores Plot",
         subtitle = "Log2 transformed data, c18 (+), outliers 6106 and 6112 removed, no QCs",
         showLoadings = F) )

biplot(p,
                               lab = NULL,
                           colby = 'pre_post_intervention',
                           colkey = c("pre_Yellow" = "lemonchiffon1",
                                        "post_Yellow" = "yellow2",
                                        "pre_Red" = "rosybrown2",
                                        "post_Red" = "darkred"),
                           hline = 0, vline = 0,
         legendPosition = 'right',
         title = "PCA Scores Plot",
         subtitle = "Log2 transformed data, c18 (+), outliers 6106 and 6112 removed, no QCs",
         showLoadings = T)

Pairs plot
(PCA_pairsplot.colby.prevspost <-
  pairsplot(p,
    components = getComponents(p, c(1:10)),
    triangle = TRUE, trianglelabSize = 12,
    hline = 0, vline = 0,
    pointSize = 0.4,
    gridlines.major = FALSE, gridlines.minor = FALSE,
    colby = 'pre_post_intervention', 
    colkey = c("pre_Yellow" = "lemonchiffon1",
                                        "post_Yellow" = "yellow2",
                                        "pre_Red" = "rosybrown2",
                                        "post_Red" = "darkred"),
    title = 'Pairs plot', plotaxes = FALSE,
    margingaps = unit(c(-0.01, -0.01, -0.01, -0.01), 'cm')))

Sex

PC1vPC2

(PCA.colby.Sex <- biplot(p,
                           lab = paste0(metadata_forPCAtools$Subject),
                          colby = 'Sex',
                          colkey = c("M" = "red",
                                     "F" = "purple"),
                          hline = 0, vline = 0,
                          legendPosition = 'right' +
                            geom_point(aes(text = metadata_forPCAtools$Subject))))

ggplotly(PCA.colby.Sex,
         tooltip = "text") 

Pairsplot

  pairsplot(p,
    components = getComponents(p, c(1:10)),
    triangle = TRUE, trianglelabSize = 12,
    hline = 0, vline = 0,
    pointSize = 0.4,
    gridlines.major = FALSE, gridlines.minor = FALSE,
    colby = 'Sex', 
    colkey = c("M" = "red",
               "F" = "purple"),
    title = 'Pairs plot', plotaxes = FALSE,
    margingaps = unit(c(-0.01, -0.01, -0.01, -0.01), 'cm'))

Pre vs post tomato

PC1vPC2

(PCA.colby.overall.prevspost <- biplot(p,
                                       lab = paste0(metadata_forPCAtools$Subject),
                                       colby = 'pre_post',
                                       colkey = c("pre" = "gray",
                                                  "post" = "darkgreen"),
                                       hline = 0, vline = 0,
                                       legendPosition = 'right' +
                                         geom_point(aes(text = metadata_forPCAtools$Subject))))

ggplotly(PCA.colby.overall.prevspost,
         tooltip = "text") 

Pairsplot

  pairsplot(p,
    components = getComponents(p, c(1:10)),
    triangle = TRUE, trianglelabSize = 12,
    hline = 0, vline = 0,
    pointSize = 0.4,
    gridlines.major = FALSE, gridlines.minor = FALSE,
    colby = 'pre_post', 
    colkey = c("pre" = "gray",
               "post" = "darkgreen"),
    title = 'Pairs plot', plotaxes = FALSE,
    margingaps = unit(c(-0.01, -0.01, -0.01, -0.01), 'cm'))

Period

Here is a good check for any period effects

PC1vPC2

(PCA.colby.period <- biplot(p,
                            lab = paste0(metadata_forPCAtools$Subject),
                            colby = 'Period',
                            hline = 0, vline = 0,
                            legendPosition = 'right' +
                              geom_point(aes(text = metadata_forPCAtools$Subject))))

ggplotly(PCA.colby.period,
         tooltip = "text") 

Pairsplot

  pairsplot(p,
    components = getComponents(p, c(1:10)),
    triangle = TRUE, trianglelabSize = 12,
    hline = 0, vline = 0,
    pointSize = 0.4,
    gridlines.major = FALSE, gridlines.minor = FALSE,
    colby = 'Period',
    title = 'Pairs plot', plotaxes = FALSE,
    margingaps = unit(c(-0.01, -0.01, -0.01, -0.01), 'cm'))

Sequence

Also looking for sequence effects

PC1vPC2

(PCA.colby.sequence <- biplot(p,
                            lab = paste0(metadata_forPCAtools$Subject),
                            colby = 'sequence',
                            hline = 0, vline = 0,
                            legendPosition = 'right' +
                              geom_point(aes(text = metadata_forPCAtools$Subject))))

ggplotly(PCA.colby.sequence,
         tooltip = "text") 

Pairsplot

  pairsplot(p,
    components = getComponents(p, c(1:10)),
    triangle = TRUE, trianglelabSize = 12,
    hline = 0, vline = 0,
    pointSize = 0.4,
    gridlines.major = FALSE, gridlines.minor = FALSE,
    colby = 'sequence',
    title = 'Pairs plot', plotaxes = FALSE,
    margingaps = unit(c(-0.01, -0.01, -0.01, -0.01), 'cm'))

Eigen corplots

This is a cool way to explore the correlations between the metadata and the PCs! I want to look at how the metavariables correlate with PCs that account for 80% variation in the dataset.

Again: How many PCs do we need to capture at least 80% variance?

which(cumsum(p$variance) > 80)[1]
## PC14 
##   14
  eigencorplot(p,
    components = getComponents(p, 1:16), # get components that account for 80% variance
    metavars = colnames(metadata_forPCAtools),
    col = c('darkblue', 'blue2', 'gray', 'red2', 'darkred'),
    cexCorval = 0.7,
    colCorval = 'white',
    fontCorval = 2,
    posLab = 'bottomleft',
    rotLabX = 45,
    posColKey = 'top',
    cexLabColKey = 1.5,
    scale = TRUE,
    main = 'PC1-14 metadata correlations',
    colFrame = 'white',
    plotRsquared = FALSE)

  eigencorplot(p,
    components = getComponents(p, 1:16),
    metavars = colnames(metadata_forPCAtools),
    col = c('white', 'cornsilk1', 'gold', 'forestgreen', 'darkgreen'),
    cexCorval = 1.2,
    fontCorval = 2,
    posLab = 'all',
    rotLabX = 45,
    scale = TRUE,
    main = bquote(Principal ~ component ~ Pearson ~ r^2 ~ metadata ~ correlates),
    plotRsquared = TRUE,
    corFUN = 'pearson',
    corUSE = 'pairwise.complete.obs',
    corMultipleTestCorrection = 'BH',
    signifSymbols = c('****', '***', '**', '*', ''),
    signifCutpoints = c(0, 0.0001, 0.001, 0.01, 0.05, 1))

I am most interested in PCs affected by pre_post_intervention, so I think it would be good to investigate the metabolites that contribute the most to these PCs.

Loadings plots

PC7/PC8

# loadings plot for PCs 7 and 8
  plotloadings(p,
    components = getComponents(p, c(7,8)),
    rangeRetain = 0.1, absolute = TRUE,
    col = c('black', 'pink', 'red4'),
    drawConnectors = TRUE, labSize = 3,
    title = "Loadings plot",
    subtitle = "PC 7 and PC 8",
    caption = "Pre_post_intervention is strongly correlated with these PCs without multiple testing correction")

Scores biplot

biplot(p,
       lab = NULL,
       x = "PC7",
       y = "PC8",
       colby = 'pre_post_intervention',
       colkey = c("pre_Yellow" = "lemonchiffon1",
                  "post_Yellow" = "yellow2",
                  "pre_Red" = "rosybrown2",
                  "post_Red" = "darkred"),
       colLegendTitle = "Intervention Timepoint",
       hline = 0, vline = 0,
       legendPosition = 'right',
       title = "PCA Scores Plot",
       subtitle = "Log2 transformed data, c18 (+), outliers removed, no QCs \n95% confidence level ellipses",
       showLoadings = TRUE)

Multilevel PCA

Data_forMPCA <- anno_imp_metabind_clust_log2_noQCs %>%
  mutate_at("Subject", as.factor)

summary(as.factor(Data_forMPCA$Subject))
## 6101 6102 6103 6104 6105 6106 6108 6109 6110 6111 6112 6113 
##    4    4    4    4    4    4    4    4    4    4    4    4
# make a vector for meta variables
(metavar <- Data_forMPCA[,c(1:11)] %>%
    colnames())
##  [1] "sample_ID"             "subj_period"           "Subject"              
##  [4] "Period"                "pre_post_intervention" "Intervention"         
##  [7] "pre_post"              "sequence"              "Intervention_week"    
## [10] "Sex"                   "Age"

Regular PCA

Remove post-red for 6112

Data_forMPCA_no6112postRed <- Data_forMPCA %>%
  filter(!((Subject == 6112) & pre_post_intervention == "post_Red"))
mixOmicsPCA.result <- mixOmics::pca(Data_forMPCA_no6112postRed[,!names(Data_forMPCA_no6112postRed) %in% metavar],
                            scale = FALSE,
                            center = T)

plotIndiv(mixOmicsPCA.result, 
          ind.names = Data_forMPCA_no6112postRed$Subject, 
          group = Data_forMPCA_no6112postRed$pre_post_intervention, 
          col.per.group = c("post_Red" = "darkred",
                            "post_Yellow" = "yellow3",
                            "pre_Red" = "rosybrown",
                            "post_Yellow" = "lemonchiffon2"),
          legend.title  = "Intervention Timepoint",
          legend = TRUE, 
          title = 'Regular PCA, c18 (+), Log2 transformed')

Multilevel PCA

pre_post_intervention

multilevelPCA.result <- mixOmics::pca(Data_forMPCA_no6112postRed[,-(c(1:11))], 
                            multilevel = Data_forMPCA_no6112postRed$Subject,
                            scale = FALSE,
                            center = TRUE)
plotIndiv(multilevelPCA.result, 
          ind.names = Data_forMPCA_no6112postRed$Subject, 
          group = Data_forMPCA_no6112postRed$pre_post_intervention, 
          col.per.group = c("post_Red" = "darkred",
                            "post_Yellow" = "yellow3",
                            "pre_Red" = "rosybrown",
                            "post_Yellow" = "lemonchiffon2"),
          legend = TRUE, 
          legend.title = "Intervention Timepoint", 
          title = 'Multilevel PCA, c18 (+), Log2 transformed')

Loadings

(loadings_multilevelPC1 <- plotLoadings(multilevelPCA.result, comp = 1, 
                                    ndisplay = 15, 
                                    title = "Top 15 features on Multilevel PC1, c18 (+)"))

##     importance
## 1   0.34486490
## 2   0.30829322
## 3   0.30706419
## 4   0.27885928
## 5   0.27522294
## 6   0.27467644
## 7   0.25562287
## 8   0.23114642
## 9   0.22320071
## 10  0.21509897
## 11  0.20597482
## 12  0.20570818
## 13  0.10473433
## 14  0.09582281
## 15 -0.08974764
(loadings_multilevelPC2 <- plotLoadings(multilevelPCA.result, comp = 2, 
                                    ndisplay = 10, 
                                    title = "Top 10 features on Multilevel PC2, c18 (+)"))

##    importance
## 1  -0.2347686
## 2  -0.1981823
## 3  -0.1605787
## 4  -0.1566305
## 5  -0.1497762
## 6  -0.1483517
## 7  -0.1441631
## 8  -0.1381850
## 9  -0.1354448
## 10 -0.1337519

Beautify

multilevelPCA_scores <- multilevelPCA.result$variates$X %>% # retrieve scores
  as.data.frame() %>%
  mutate(sample_ID = Data_forMPCA_no6112postRed$sample_ID)

# join with metadata
multilevelPCA_points <- left_join(multilevelPCA_scores, Data_forMPCA_no6112postRed[,1:11]) 
Scores
# visualize!
(plot_multilevelPCA_manual <- multilevelPCA_points %>% 
  ggplot(aes(x = PC1, y = PC2, 
             fill = factor(pre_post_intervention, levels = c("pre_Yellow",
                                                             "post_Yellow",
                                                             "pre_Red",
                                                             "post_Red")),
             text = sample_ID)) +
    geom_point(shape = 21, alpha = 0.8) +
    geom_hline(yintercept = 0, linetype = "dashed", alpha=0.5) +
    geom_vline(xintercept = 0, linetype = "dashed", alpha=0.5) +
    scale_fill_manual(values = c("lemonchiffon1",
                                 "yellow2",
                                 "rosybrown2",
                                 "darkred")) +
    scale_color_manual(values = "black") +  
    theme_minimal() +
    labs(x = "PC1, 12% variation",
         y = "PC2, 9% variation",
         fill = "Timepoint",
         title = "Multilevel Principal Components Analysis Scores Plot",
         subtitle = "Log2 transformed data, c18 (+) without outlier subjects"))

ggplotly(plot_multilevelPCA_manual,
         tooltip = "text")
Biplot
# retrieve loadings
multilevelPCA_loadings <- multilevelPCA.result$loadings$X %>%
  as.data.frame() %>%
  rownames_to_column("mz_rt")
multilevelPCA_loadings %>%
  filter(PC1 %in% loadings_multilevelPC1$importance
         | PC2 %in% loadings_multilevelPC2$importance) %>%
  ggplot(aes(x = PC1, y = PC2, label = mz_rt)) +
  geom_hline(yintercept = 0, linetype = "dashed") +
  geom_vline(xintercept = 0, linetype = "dashed") +
  geom_point() +
  geom_label_repel(size = 2.5) +
  scale_fill_brewer() +
  theme_minimal() +
  labs( x = "PC1, 12% variation",
         y = "PC2, 9% variation",
       title = "Loadings Plot for Multilevel PCA",
       subtitle = "c18 (+) \nSubj 6112 at post Tomato-Soy timepoint removed",)

# fx to normalize scores so that scores and loadings are on the same scale
normalize <- function(x) return((x - min(x))/(max(x) - min(x)))
# normalize scores
multilevelPCA_scores_normalized <- multilevelPCA_scores %>%
  mutate(PC1_norm = scale(normalize(PC1), center = TRUE, scale = FALSE)) %>%
  mutate(PC2_norm = scale(normalize(PC2), center = TRUE, scale = FALSE)) %>%
  select(sample_ID, PC1_norm, PC2_norm, everything()) # reorder 

How did it go? PC1_norm and PC2_norm should all now be between -1 and 1

head(multilevelPCA_scores_normalized) # looks good
##             sample_ID   PC1_norm    PC2_norm       PC1         PC2
## 1   6101_U1_C18POS_59 -0.2138453 -0.05379039 -5.911001  -1.3153606
## 2 6102_U1_C18POS_26_1 -0.2342625  0.20610802 -6.475361   5.0400525
## 3   6103_U1_C18POS_21 -0.1608187 -0.01839624 -4.445267  -0.4498515
## 4   6104_U1_C18POS_55 -0.1608947  0.06093929 -4.447366   1.4901760
## 5   6105_U1_C18POS_43 -0.1647088 -0.34637962 -4.552794  -8.4701773
## 6   6106_U1_C18POS_23 -0.2701061 -0.41273960 -7.466132 -10.0929078

Now we can plot together the scores and loadings in one plot.

# join with metadata
multilevelPCA_points_norm <- left_join(multilevelPCA_scores_normalized, Data_forMPCA_no6112postRed[,1:11]) 
multilevelPCA_points_norm %>%
  ggplot() +
  geom_hline(yintercept = 0, linetype = "dashed") +
  geom_vline(xintercept = 0, linetype = "dashed") +
  geom_point(aes(x = PC1_norm, y = PC2_norm, 
                 fill = factor(pre_post_intervention, 
                               levels = c("pre_Yellow",
                                          "post_Yellow",
                                          "pre_Red",
                                          "post_Red"))),
             inherit.aes = F,
             shape = 21) +
  geom_segment(data = multilevelPCA_loadings %>%
                 filter(PC1 %in% loadings_multilevelPC1$importance
                        | PC2 %in% loadings_multilevelPC2$importance), 
               aes(x = 0, y = 0, 
                   xend = (PC1*4), yend = (PC2*4)), 
               arrow = arrow(length = unit(1/2, "picas")),
                                color = "black", alpha=0.55) +
  geom_label_repel(data = multilevelPCA_loadings %>%
                    filter(PC1 %in% loadings_multilevelPC1$importance
                        | PC2 %in% loadings_multilevelPC2$importance),
                   aes(x = PC1*4.6, y = PC2*5, label = mz_rt), 
                   size = 2.5, segment.color = "transparent",
                   direction = "both", max.overlaps = 15) +
  scale_fill_manual(values = c("lemonchiffon1",
                                 "yellow2",
                                 "rosybrown2",
                                 "darkred")) +
  theme_minimal() +
  labs(x = "PC1, 12% variation",
         y = "PC2, 9% variation",
       title = "Biplot for Multilevel PCA",
       subtitle = "c18 (+) \nSubj 6112 at post Tomato-Soy timepoint removed",
       fill = "Timepoint",
       caption = "")

multilevelPCA_points_norm %>%
  ggplot() +
  geom_hline(yintercept = 0, linetype = "dashed") +
  geom_vline(xintercept = 0, linetype = "dashed") +
  geom_point(aes(x = PC1_norm, y = PC2_norm, 
                 fill = factor(pre_post_intervention, 
                               levels = c("pre_Yellow",
                                          "post_Yellow",
                                          "pre_Red",
                                          "post_Red"))),
             inherit.aes = F,
             shape = 21) +
  geom_label_repel(data = multilevelPCA_loadings %>%
                    filter(PC1 %in% loadings_multilevelPC1$importance
                        | PC2 %in% loadings_multilevelPC2$importance),
                   aes(x = PC1*4.6, y = PC2*5, label = mz_rt), 
                   size = 2.5, segment.color = "transparent",
                   direction = "both", max.overlaps = 15) +
  scale_fill_manual(values = c("lemonchiffon1",
                                 "yellow2",
                                 "rosybrown2",
                                 "darkred"),
                    labels = c("pre control",
                               "post control",
                               "pre tomato-soy",
                               "post tomato-soy")) +
  theme_minimal() +
  labs(x = "PC1, 12% variation",
         y = "PC2, 9% variation",
       title = "Biplot for Multilevel PCA",
       subtitle = "c18 (+) \nSubj 6112 at post Tomato-Soy timepoint removed",
       caption = "",
       fill = "Timepoint")

pre_post

multilevelPCA.result <- mixOmics::pca(Data_forMPCA[,-(c(1:11))], 
                            multilevel = Data_forMPCA$Subject,
                            scale = FALSE,
                            center = FALSE)

plotIndiv(multilevelPCA.result, 
          ind.names = Data_forMPCA$Subject, 
          group = Data_forMPCA$pre_post, 
          legend = TRUE, 
          legend.title = "Treatment", 
          title = 'Multilevel PCA, c18 (+), Log2 transformed')

Loadings

plotLoadings(multilevelPCA.result, ndisplay = 15, comp = 2)

Univariate analysis

Wrangle data

use tidy data

# use tidy data 
head(anno_imp_metabind_clust_tidy_log2)
## # A tibble: 6 × 18
##   sample_ID        subj_period Subject Period pre_post_intervention Intervention
##   <chr>            <chr>       <chr>   <chr>  <chr>                 <chr>       
## 1 6101_U1_C18POS_… 6101_U1     6101    U1     pre_Red               Red         
## 2 6101_U1_C18POS_… 6101_U1     6101    U1     pre_Red               Red         
## 3 6101_U1_C18POS_… 6101_U1     6101    U1     pre_Red               Red         
## 4 6101_U1_C18POS_… 6101_U1     6101    U1     pre_Red               Red         
## 5 6101_U1_C18POS_… 6101_U1     6101    U1     pre_Red               Red         
## 6 6101_U1_C18POS_… 6101_U1     6101    U1     pre_Red               Red         
## # ℹ 12 more variables: pre_post <chr>, sequence <chr>, Intervention_week <chr>,
## #   Sex <chr>, Age <chr>, BMI <chr>, mz_rt <chr>, rel_abund_log2 <dbl>,
## #   annotation <chr>, metabolite_class <chr>, parent_compound <chr>,
## #   Feature_ID <chr>
# remove QCs
df_for_stats <- anno_imp_metabind_clust_tidy_log2 %>%
  filter(Intervention != "QC")

# check if QCs were removed
unique(df_for_stats$Intervention)
## [1] "Red"    "Yellow"
# df without outliers
df_for_stats_noOutlier <- df_for_stats %>%
  filter(Subject != "6106",
         Subject != "6112")

# check if outlier was removed
unique(df_for_stats_noOutlier$Subject)
##  [1] "6101" "6102" "6103" "6104" "6105" "6108" "6109" "6110" "6111" "6113"
# turn off sci notation outputs
options(scipen = 999)

Parametric tests

ANOVA (repeated measures) across timepoints

anova_outpout_df <- df_for_stats_noOutlier %>%
  dplyr::select(Subject, pre_post_intervention, Feature_ID, rel_abund_log2) %>%
  group_by(Feature_ID) %>%
  anova_test(rel_abund_log2 ~ pre_post_intervention, wid = Subject,
             detailed = TRUE) %>%
  adjust_pvalue(method = "BH") %>%
  as.data.frame()

anova_sig <- anova_outpout_df %>%
  filter(p.adj <= 0.05)

# how many significant features?
nrow(anova_sig)
## [1] 20
# tukey's posthoc
tukey_anova <- df_for_stats_noOutlier %>% 
  dplyr::select(Subject, pre_post_intervention, Feature_ID, rel_abund_log2) %>%
  group_by(Feature_ID) %>%
  tukey_hsd(rel_abund_log2 ~ pre_post_intervention, wid = subject)

boxplots

df_for_stats_noOutlier %>% 
  filter(Feature_ID %in% anova_sig$Feature_ID) %>%
  ggplot(aes(x = factor(pre_post_intervention,
                        levels = c("pre_Yellow", "post_Yellow", 
                                   "pre_Red", "post_Red")), 
             y = rel_abund_log2, fill = Intervention)) +
  geom_boxplot(outlier.shape = NA) +
  scale_fill_manual(values = c("Yellow" = "gold",
                                           "Red" = "tomato1")) +
  geom_line(aes(group = Subject), linewidth = 0.2) +
  facet_wrap(vars(Feature_ID), scales = "free_y") + 
  theme_clean()

Heatmap of features significant by ANOVA

ANOVA_heatmap_data <- anno_imp_metabind_clust_log2_noQCs %>%
  unite("Subject_pre_post_intervention", Subject, pre_post_intervention, sep = "_", remove = FALSE) %>%
  dplyr::select(sample_ID, Subject, Subject_pre_post_intervention, pre_post_intervention, all_of(anova_sig$Feature_ID)) %>%
  column_to_rownames("sample_ID")

ANOVA_heatmap <- 
  pheatmap(t(ANOVA_heatmap_data[,-c(1:3)]),
           scale = "row",
           cluster_rows = TRUE,
           clustering_distance_rows = "euclidean",
           clustering_distance_cols = "euclidean",
           clustering_method = "ward.D2",
           labels_col = ANOVA_heatmap_data$Subject_pre_post_intervention,
           color = colorRampPalette(c("#67a9cf", "#f7f7f7", "#ef8a62"))(16),
           main = "Heatmap of features significant across timepoints \nby repeated measures one-way ANOVA \nBenjamoni-Hochberg corrected p-values > 0.05 \nc18 (+)")

ANOVA_heatmap_data2 <- anno_imp_metabind_clust_log2_noQCs %>%
  filter(Subject != 6106,
         Subject != 6112) %>%
  unite("Subject_pre_post_intervention", Subject, pre_post_intervention, sep = "_", remove = FALSE) %>%
  dplyr::select(sample_ID, Subject_pre_post_intervention, pre_post_intervention, all_of(anova_sig$Feature_ID)) %>%
  column_to_rownames("sample_ID") 
# i need wide df
df_for_stats_noOutlier_wide <- df_for_stats_noOutlier %>%
  select(1:11, Feature_ID, rel_abund_log2) %>%
  pivot_wider(names_from = "Feature_ID",
              values_from = "rel_abund_log2")

# change pre_post_intervention to factor
df_for_stats_noOutlier_wide$pre_post_intervention <- as.factor(df_for_stats_noOutlier_wide$pre_post_intervention)

# create annotation rows for treatment and wrangle
# select sample col from heatmap metadata (also ensures the order is correct)
anno_trt_row <- as.data.frame(rownames(ANOVA_heatmap_data2))

# pull desired columns
anno_trt_row$pre_post_intervention <- ANOVA_heatmap_data2$pre_post_intervention

# select trt
anno_trt_row <- anno_trt_row %>%
  dplyr::select(pre_post_intervention) 

# get rownames to match heatmap
rownames(anno_trt_row) <- rownames(ANOVA_heatmap_data2)

# create annotation colors
annotation_colors <- list(pre_post_intervention = c("pre_Yellow" = "lemonchiffon1",
                                                    "post_Yellow" = "yellow2",
                                                    "pre_Red" = "rosybrown2",
                                                    "post_Red" = "darkred"))
(ANOVA_heatmap <- 
  pheatmap(t(ANOVA_heatmap_data2[,-c(1:2)]),
           scale = "row",
           cluster_rows = TRUE,
           clustering_distance_rows = "euclidean",
           clustering_distance_cols = "euclidean",
           clustering_method = "ward.D2",
           labels_col = ANOVA_heatmap_data2$Subject_pre_post_intervention,
           color = colorRampPalette(c("#67a9cf", "#f7f7f7", "#ef8a62"))(16),
           annotation_col = anno_trt_row,
           annotation_colors = annotation_colors,
           annotation_names_col = F,
           main = "Heatmap of features significant across timepoints \nby repeated measures one-way ANOVA \nBenjamoni-Hochberg corrected p-values > 0.05 \nRPLC-MS (+)"))

ggsave(plot = ANOVA_heatmap, height = 8, width = 12,
       filename = "plots and figures/RPLCMSPOS_heatmap_ANOVAsig.svg")

Paired t tests

Here, I am comparing pre- to post-intervention for both yellow and tomato soy (Red) juice interventions. I also compare post-yellow to post-red intervention. I am using the log transformed values of rel abundance since parametric tests assume normality.

Ctrl

# run paired t-tests for control intervention
ctrl_t.test_paired <- df_for_stats %>%
  filter(Intervention == "Yellow") %>%
  dplyr::select(Subject, pre_post, mz_rt, rel_abund_log2) %>%
  group_by(mz_rt) %>%
  t_test(rel_abund_log2 ~ pre_post, 
         paired = TRUE, 
         p.adjust.method = "BH") %>% # Benjamini-Hochberg controlling to lower false positives
  add_significance()

Statistically significant features

# which features are significant?
ctrl_t.test_paired_sig <- ctrl_t.test_paired %>%
  filter(p <= 0.05)
tibble(ctrl_t.test_paired_sig)
## # A tibble: 148 × 10
##    mz_rt        .y.   group1 group2    n1    n2 statistic    df       p p.signif
##    <chr>        <chr> <chr>  <chr>  <int> <int>     <dbl> <dbl>   <dbl> <chr>   
##  1 100.0756_0.… rel_… post   pre       12    12     -2.33    11 4.02e-2 *       
##  2 111.044_2.9… rel_… post   pre       12    12     -2.40    11 3.55e-2 *       
##  3 114.0669_0.… rel_… post   pre       12    12     -2.43    11 3.35e-2 *       
##  4 132.0768_0.… rel_… post   pre       12    12     -3.63    11 3.98e-3 **      
##  5 136.0482_0.… rel_… post   pre       12    12      3.28    11 7.3 e-3 **      
##  6 141.0659_0.… rel_… post   pre       12    12     -2.50    11 2.92e-2 *       
##  7 142.0862_0.… rel_… post   pre       12    12     -3.26    11 7.57e-3 **      
##  8 149.0598_7.… rel_… post   pre       12    12      2.56    11 2.65e-2 *       
##  9 156.0769_0.… rel_… post   pre       12    12     -4.69    11 6.63e-4 ***     
## 10 159.1492_0.… rel_… post   pre       12    12     -2.65    11 2.24e-2 *       
## # ℹ 138 more rows
# how many are significant?
nrow(ctrl_t.test_paired_sig)
## [1] 148

Ctrl no outlier

# run paired t-tests for control intervention
ctrl_noOutlier_t.test_paired <- df_for_stats_noOutlier %>%
  filter(Intervention == "Yellow") %>%
  dplyr::select(Subject, pre_post, mz_rt, rel_abund_log2) %>%
  group_by(mz_rt) %>%
  t_test(rel_abund_log2 ~ pre_post, 
         paired = TRUE, 
         p.adjust.method = "BH") %>% # Benjamini-Hochberg controlling to lower false positives
  add_significance()

Statistically significant features

# which features are significant?
ctrl_noOutlier_t.test_paired_sig <- ctrl_noOutlier_t.test_paired %>%
  filter(p <= 0.05)
tibble(ctrl_noOutlier_t.test_paired_sig)
## # A tibble: 98 × 10
##    mz_rt        .y.   group1 group2    n1    n2 statistic    df       p p.signif
##    <chr>        <chr> <chr>  <chr>  <int> <int>     <dbl> <dbl>   <dbl> <chr>   
##  1 132.0768_0.… rel_… post   pre       10    10     -3.15     9 0.0117  *       
##  2 136.0482_0.… rel_… post   pre       10    10      2.58     9 0.0296  *       
##  3 142.0862_0.… rel_… post   pre       10    10     -2.82     9 0.02    *       
##  4 144.1283_0.… rel_… post   pre       10    10      2.33     9 0.0448  *       
##  5 156.0769_0.… rel_… post   pre       10    10     -4.13     9 0.00255 **      
##  6 162.1126_0.… rel_… post   pre       10    10     -3.12     9 0.0124  *       
##  7 163.1243_0.… rel_… post   pre       10    10     -3.98     9 0.00322 **      
##  8 166.0862_0.… rel_… post   pre       10    10     -3.49     9 0.0068  **      
##  9 170.0926_0.… rel_… post   pre       10    10     -2.98     9 0.0155  *       
## 10 174.1237_2.… rel_… post   pre       10    10      4.06     9 0.00283 **      
## # ℹ 88 more rows
# how many are significant?
nrow(ctrl_noOutlier_t.test_paired_sig)
## [1] 98

Red

# run paired t-tests for control intervention
red_t.test_paired <- df_for_stats %>%
  filter(Intervention == "Red") %>%
  dplyr::select(Subject, pre_post, mz_rt, rel_abund_log2) %>%
  group_by(mz_rt) %>%
  t_test(rel_abund_log2 ~ pre_post, 
         paired = TRUE, 
         p.adjust.method = "BH") %>% # Benjamini-Hochberg controlling to lower false positives
  add_significance()

Statistically significant features

# which features are significant?
red_t.test_paired_sig <- red_t.test_paired %>%
  filter(p <= 0.05)
tibble(red_t.test_paired_sig)
## # A tibble: 79 × 10
##    mz_rt        .y.   group1 group2    n1    n2 statistic    df       p p.signif
##    <chr>        <chr> <chr>  <chr>  <int> <int>     <dbl> <dbl>   <dbl> <chr>   
##  1 111.044_2.9… rel_… post   pre       12    12     -2.27    11 0.0439  *       
##  2 121.0284_3.… rel_… post   pre       12    12      3.24    11 0.00789 **      
##  3 135.0441_3.… rel_… post   pre       12    12     -3.16    11 0.00908 **      
##  4 144.1023_0.… rel_… post   pre       12    12     -3.21    11 0.00824 **      
##  5 145.0648_5.… rel_… post   pre       12    12     -3.31    11 0.0069  **      
##  6 160.0967_0.… rel_… post   pre       12    12     -3.80    11 0.00295 **      
##  7 166.0863_2.… rel_… post   pre       12    12     -2.44    11 0.0328  *       
##  8 170.0447_0.… rel_… post   pre       12    12      2.70    11 0.0207  *       
##  9 170.0448_2.… rel_… post   pre       12    12      2.74    11 0.0194  *       
## 10 190.0499_3.… rel_… post   pre       12    12     -2.73    11 0.0196  *       
## # ℹ 69 more rows
# how many are significant?
nrow(red_t.test_paired_sig)
## [1] 79

Red no outlier

# run paired t-tests for control intervention
red_noOutlier_t.test_paired <- df_for_stats_noOutlier %>%
  filter(Intervention == "Red") %>%
  dplyr::select(Subject, pre_post, mz_rt, rel_abund_log2) %>%
  group_by(mz_rt) %>%
  t_test(rel_abund_log2 ~ pre_post, 
         paired = TRUE, 
         p.adjust.method = "BH") %>% # Benjamini-Hochberg controlling to lower false positives
  add_significance()

Statistically significant features

# which features are significant?
red_noOutlier_t.test_paired_sig <- red_noOutlier_t.test_paired %>%
  filter(p <= 0.05)
tibble(red_noOutlier_t.test_paired_sig)
## # A tibble: 69 × 10
##    mz_rt        .y.   group1 group2    n1    n2 statistic    df       p p.signif
##    <chr>        <chr> <chr>  <chr>  <int> <int>     <dbl> <dbl>   <dbl> <chr>   
##  1 121.0284_3.… rel_… post   pre       10    10      3.51     9 0.00665 **      
##  2 121.0646_4.… rel_… post   pre       10    10      3.45     9 0.0073  **      
##  3 135.0441_3.… rel_… post   pre       10    10     -2.76     9 0.022   *       
##  4 138.0551_0.… rel_… post   pre       10    10      2.76     9 0.0223  *       
##  5 144.1023_0.… rel_… post   pre       10    10     -2.95     9 0.0162  *       
##  6 145.0648_5.… rel_… post   pre       10    10     -2.66     9 0.0259  *       
##  7 160.0967_0.… rel_… post   pre       10    10     -3.76     9 0.0045  **      
##  8 166.0863_2.… rel_… post   pre       10    10     -2.29     9 0.0481  *       
##  9 190.0499_3.… rel_… post   pre       10    10     -2.37     9 0.0417  *       
## 10 196.0604_3.… rel_… post   pre       10    10      3.25     9 0.00993 **      
## # ℹ 59 more rows
# how many are significant?
nrow(red_noOutlier_t.test_paired_sig)
## [1] 69

Post-red vs post-yellow

# run paired t-tests for post interventions
post_t.test_paired <- df_for_stats %>%
  filter(pre_post == "post") %>%
  dplyr::select(Subject, Intervention, mz_rt, rel_abund_log2) %>%
  group_by(mz_rt) %>%
  t_test(rel_abund_log2 ~ Intervention, 
         paired = TRUE, 
         p.adjust.method = "BH") %>% # Benjamini-Hochberg controlling to lower false positives
  add_significance()

Statistically significant features

# which features are significant?
post_t.test_paired_sig <- post_t.test_paired %>%
  filter(p <= 0.05)
tibble(post_t.test_paired_sig)
## # A tibble: 28 × 10
##    mz_rt        .y.   group1 group2    n1    n2 statistic    df       p p.signif
##    <chr>        <chr> <chr>  <chr>  <int> <int>     <dbl> <dbl>   <dbl> <chr>   
##  1 203.139_0.6… rel_… Red    Yellow    12    12      2.33    11 3.99e-2 *       
##  2 234.1122_4.… rel_… Red    Yellow    12    12     -6.51    11 4.38e-5 ****    
##  3 250.1107_3.… rel_… Red    Yellow    12    12     -4.16    11 1.59e-3 **      
##  4 255.0655_5.… rel_… Red    Yellow    12    12     10.2     11 5.95e-7 ****    
##  5 271.0596_4.… rel_… Red    Yellow    12    12     13.3     11 4.1 e-8 ****    
##  6 271.1656_4.… rel_… Red    Yellow    12    12      2.33    11 3.98e-2 *       
##  7 274.1833_5.… rel_… Red    Yellow    12    12      2.36    11 3.8 e-2 *       
##  8 277.1432_7.… rel_… Red    Yellow    12    12      3.90    11 2.47e-3 **      
##  9 292.1575_3.… rel_… Red    Yellow    12    12     -2.25    11 4.57e-2 *       
## 10 302.1959_0.… rel_… Red    Yellow    12    12      2.71    11 2.02e-2 *       
## # ℹ 18 more rows
# how many are significant?
nrow(post_t.test_paired_sig)
## [1] 28

Post-red vs post-yellow no Outlier

# run paired t-tests for post interventions
post_noOutlier_t.test_paired <- df_for_stats %>%
  filter(pre_post == "post",
         Subject != "6106") %>%
  dplyr::select(Subject, Intervention, mz_rt, rel_abund_log2) %>%
  group_by(mz_rt) %>%
  t_test(rel_abund_log2 ~ Intervention, 
         paired = TRUE, 
         p.adjust.method = "BH") %>% # Benjamini-Hochberg controlling to lower false positives
  add_significance()

Statistically significant features

# which features are significant?
post_noOutlier_t.test_paired_sig <- post_noOutlier_t.test_paired %>%
  filter(p <= 0.05)
tibble(post_noOutlier_t.test_paired_sig)
## # A tibble: 32 × 10
##    mz_rt        .y.   group1 group2    n1    n2 statistic    df       p p.signif
##    <chr>        <chr> <chr>  <chr>  <int> <int>     <dbl> <dbl>   <dbl> <chr>   
##  1 142.0862_0.… rel_… Red    Yellow    11    11      2.56    10 2.83e-2 *       
##  2 159.1492_0.… rel_… Red    Yellow    11    11      2.98    10 1.39e-2 *       
##  3 160.0967_0.… rel_… Red    Yellow    11    11     -2.24    10 4.86e-2 *       
##  4 219.1705_0.… rel_… Red    Yellow    11    11     -2.36    10 3.97e-2 *       
##  5 230.9902_0.… rel_… Red    Yellow    11    11     -2.56    10 2.86e-2 *       
##  6 234.1122_4.… rel_… Red    Yellow    11    11     -4.55    10 1.05e-3 **      
##  7 250.1107_3.… rel_… Red    Yellow    11    11     -2.82    10 1.8 e-2 *       
##  8 255.0655_5.… rel_… Red    Yellow    11    11      9.28    10 3.15e-6 ****    
##  9 265.1278_3.… rel_… Red    Yellow    11    11      2.28    10 4.56e-2 *       
## 10 271.0596_4.… rel_… Red    Yellow    11    11     11.6     10 4.08e-7 ****    
## # ℹ 22 more rows
# how many are significant?
nrow(post_noOutlier_t.test_paired_sig)
## [1] 32

Volcano plots

Post-intervention comparisons

Wrangle (no outlier)
# calculate mean rel abund (not log) by sample, and avg fold change (FC) diff by feature
red_v_yel_volcano_data_noOutlier <- df_for_stats %>%
  filter(pre_post == "post",
         Subject != 6106,
         Subject != 6112) %>% # remove outlier subj
  group_by(Intervention, mz_rt) %>%
  summarize(mean_rel_abund = mean(2^rel_abund_log2)) %>%
  pivot_wider(names_from = Intervention, values_from = mean_rel_abund) %>%
  mutate(FC_postRed_div_postYellow = Red/Yellow) 

# bind back pval
red_v_yel_tobind_noOutlier <- post_noOutlier_t.test_paired %>%
  dplyr::select(p)

# calculate log2FC, and -log10p
red_v_yel_volcano_data_noOutlier <- 
  bind_cols(red_v_yel_volcano_data_noOutlier, red_v_yel_tobind_noOutlier) %>%
  mutate(log2_FC_postRed_div_postYellow = if_else(FC_postRed_div_postYellow > 0,
                                                  log2(FC_postRed_div_postYellow),
                                                  -(log2(abs(FC_postRed_div_postYellow)))), 
         neglog10p = -log10(p))


# create a df of features passing FC and pval cutoffs higher in post-Red
postRed_sig_red_v_yel_volcano_noOutlier <- red_v_yel_volcano_data_noOutlier %>%
  filter(p <= 0.05 & log2_FC_postRed_div_postYellow >= 0.6)

# create a df of features passing FC and pval cutoffs higher in post-control
postYellow_sig_red_v_yel_volcano_noOutlier <- red_v_yel_volcano_data_noOutlier %>%
  filter(p <= 0.05 & log2_FC_postRed_div_postYellow <= -0.6)  
Export sig features

Create feature lists with significant features along with their clusters

#post-Red list
postRed_sig_intrvntn_comp_clusters <- left_join(postRed_sig_red_v_yel_volcano_noOutlier, cluster_features,
                                               by = "mz_rt")

write_csv(postRed_sig_intrvntn_comp_clusters,
          "Feature lists/postRed-sigfeatures-intervntn-comp.csv")

#post-Yellow list
postYellow_sig_intrvntn_comp_clusters <- left_join(postYellow_sig_red_v_yel_volcano_noOutlier, cluster_features,
                                               by = "mz_rt")

write_csv(postYellow_sig_intrvntn_comp_clusters,
          "Feature lists/postYellow-sigfeatures-intervntn-comp.csv")
Plot
(red_v_yellow_volcano_noOutlier <- red_v_yel_volcano_data_noOutlier %>%
  ggplot(aes(x = log2_FC_postRed_div_postYellow, y = neglog10p, 
             text = glue("Mass_retention time: {mz_rt}
                         P-value: {p}
                         Fold change tomato/control: {round(FC_postRed_div_postYellow, 2)}"))) +
  geom_point(color = "grey") +
  geom_point(data = postRed_sig_intrvntn_comp_clusters, 
             aes(x = log2_FC_postRed_div_postYellow, y = neglog10p),
             color = "tomato") +
  geom_point(data = postYellow_sig_intrvntn_comp_clusters, 
             aes(x = log2_FC_postRed_div_postYellow, y = neglog10p),
             color = "yellow2") +
  geom_vline(xintercept = 0.6, linetype = "dashed", color = "grey") +
  geom_vline(xintercept = -0.6, linetype = "dashed", color = "grey") +
  geom_hline(yintercept = 1.3, linetype = "dashed", color = "grey") +
  coord_cartesian(xlim = c(-5, 8)) +
  labs(title = "Volcano Plot of Features Different in People After Tomato-Soy and Control Juice Consumption",
       subtitle = "Red points are higher after tomato-soy juice consumption while yellow points are higher \nafter control tomato juice consumption. Subject 6106 removed",
       caption = "Vertical dashed lines represent a log2 fold change > 0.6 or < -0.6, and horizontal dashed line represents an FDR corrected \np-value of 0.05.",
       x = "Log2 Fold Change (TomatoSoy/Control)",
       y = "-Log10(P-value)") +
  theme_bw() +
  theme(plot.title = element_text(size = 12, hjust = 0),
        plot.caption = element_text(hjust = 0.5)))

(red_v_yellow_volcano_ggplotly_noOutlier <- ggplotly(red_v_yellow_volcano_noOutlier, tooltip = "text"))

Save plots

# save volcano plot
ggsave(plot = red_v_yellow_volcano_noOutlier,
       filename = "plots and figures/volcano plots/red_v_yellow_volcano_noOutlier.svg")

# save interactive volcano plot
saveWidget(widget = red_v_yellow_volcano_ggplotly_noOutlier,
           file = "plots and figures/volcano plots/interactive_redvyellow_volcano_plot_noOutlier.html")

Red

Wrangle (no outlier)
# calculate mean rel abund (not log) by sample, and avg fold change (FC) diff by feature
red_volcano_data_noOutlier <- df_for_stats %>%
  filter(Intervention == "Red",
         Subject != 6106,
         Subject != 6112) %>%
  group_by(pre_post, mz_rt) %>%
  summarize(mean_rel_abund = mean(2^rel_abund_log2)) %>%
  pivot_wider(names_from = pre_post, values_from = mean_rel_abund) %>%
  mutate(FC_post_div_pre = post/pre) 

# bind back pval
red_tobind_noOutlier <- red_noOutlier_t.test_paired %>%
  dplyr::select(p)

# calculate log2FC, and -log10p
red_volcano_data_noOutlier <- 
  bind_cols(red_volcano_data_noOutlier, red_tobind_noOutlier) %>%
  mutate(log2_FC_post_div_pre = log2(FC_post_div_pre),
         neglog10p = -log10(p))


# create a df of features passing FC and pval cutoffs higher in post-intervention compared to pre
red_pre_v_post_volcano_noOutlier <- red_volcano_data_noOutlier %>%
  filter(p <= 0.05 & abs(log2_FC_post_div_pre) >= 0.6)
Export sig features

Create feature lists with significant features along with their clusters

red_sig_prepost_comp_clusters <- left_join(red_pre_v_post_volcano_noOutlier, cluster_features,
                                               by = "mz_rt")

write_csv(red_sig_prepost_comp_clusters,
          "Feature lists/Red-sigfeatures-PrevsPost-noOutliers.csv")
Plot
(red_volcano_noOutlier <- red_volcano_data_noOutlier %>%
  ggplot(aes(x = log2_FC_post_div_pre, y = neglog10p, 
             text = glue("Mass_retention time: {mz_rt}
                         P-value: {p}
                         Fold change post/pre: {round(FC_post_div_pre, 2)}"))) +
  geom_point(color = "grey") +
  geom_point(data = red_sig_prepost_comp_clusters, 
             aes(x = log2_FC_post_div_pre, y = neglog10p),
             color = "tomato") +
  geom_vline(xintercept = 0.6, linetype = "dashed", color = "grey") +
  geom_vline(xintercept = -0.6, linetype = "dashed", color = "grey") + 
  geom_hline(yintercept = 1.3, linetype = "dashed", color = "grey") +
  coord_cartesian(xlim = c(-5, 6)) +
  labs(title = "Volcano Plot of Features Different in People After Tomato-Soy Juice Consumption",
       subtitle = "Red points are higher after tomato-soy juice consumption when compared to prior to consumption",
       caption = "Vertical dashed lines represent an abs(log fold change) > 0.6, and horizontal dashed line represents an FDR corrected \np-value of 0.05.",
       x = "Log2 Fold Change (Post/Pre)",
       y = "-Log10(P-value)") +
  theme_bw() +
  theme(plot.title = element_text(size = 12, hjust = 0),
        plot.caption = element_text(hjust = 0.5)))

(red_volcano_ggplotly_noOutlier <- ggplotly(red_volcano_noOutlier, tooltip = "text"))

Save plots

# save volcano plot
ggsave(plot = red_volcano_noOutlier,
       filename = "plots and figures/volcano plots/red_volcano_noOutlier.svg")

# save interactive volcano plot
saveWidget(widget = red_volcano_ggplotly_noOutlier,
           file = "plots and figures/volcano plots/interactive_red_volcano_plot_noOutlier.html")

Yellow

Wrangle (no outlier)
# calculate mean rel abund (not log) by sample, and avg fold change (FC) diff by feature
yel_volcano_data_noOutlier <- df_for_stats %>%
  filter(Intervention == "Yellow",
         Subject != 6106,
         Subject != 6112) %>%
  group_by(pre_post, mz_rt) %>%
  summarize(mean_rel_abund = mean(2^rel_abund_log2)) %>%
  pivot_wider(names_from = pre_post, values_from = mean_rel_abund) %>%
  mutate(FC_post_div_pre = post/pre) 

# bind back pval
yel_tobind_noOutlier <- ctrl_noOutlier_t.test_paired %>%
  dplyr::select(p)

# calculate log2FC, and -log10p
yel_volcano_data_noOutlier <- 
  bind_cols(yel_volcano_data_noOutlier, yel_tobind_noOutlier) %>%
  mutate(log2_FC_post_div_pre = log2(FC_post_div_pre),
         neglog10p = -log10(p))


# create a df of features passing FC and pval cutoffs higher in post-intervention compared to pre
yel_pre_v_post_volcano_noOutlier <- yel_volcano_data_noOutlier %>%
  filter(p <= 0.05 & abs(log2_FC_post_div_pre) >= 0.6)
Export sig features

Create feature lists with significant features along with their clusters

yel_sig_prepost_comp_clusters <- left_join(yel_pre_v_post_volcano_noOutlier, cluster_features,
                                               by = "mz_rt")

write_csv(yel_sig_prepost_comp_clusters,
          "Feature lists/Yellow-sigfeatures-PrevsPost-noOutliers.csv")
Plot
(yel_volcano_noOutlier <- yel_volcano_data_noOutlier %>%
  ggplot(aes(x = log2_FC_post_div_pre, y = neglog10p, 
             text = glue("Mass_retention time: {mz_rt}
                         P-value: {p}
                         Fold change post/pre: {round(FC_post_div_pre, 2)}"))) +
  geom_point(color = "grey") +
  geom_point(data = yel_sig_prepost_comp_clusters, 
             aes(x = log2_FC_post_div_pre, y = neglog10p),
             color = "yellow2") +
  geom_vline(xintercept = 0.6, linetype = "dashed", color = "grey") +
  geom_vline(xintercept = -0.6, linetype = "dashed", color = "grey") +
  geom_hline(yintercept = 1.3, linetype = "dashed", color = "grey") +
  coord_cartesian(xlim = c(-6, 6)) +
  labs(title = "Volcano Plot of Features Different in People After Control, Yellow Tomato Juice Consumption",
       subtitle = "Yellow points are higher after control juice consumption when compared to prior to consumption.\nSubject 6106 removed",
       caption = "Vertical dashed lines represent abs(log2 fold change) > 0.6, and horizontal dashed line represents an FDR corrected \np-value of 0.05.",
       x = "Log2 Fold Change (Post/Pre)",
       y = "-Log10(P-value)") +
  theme_bw() +
  theme(plot.title = element_text(size = 12, hjust = 0),
        plot.caption = element_text(hjust = 0.5)))

(yel_volcano_ggplotly_noOutlier <- ggplotly(yel_volcano_noOutlier, tooltip = "text"))

Save plots

# save volcano plot
ggsave(plot = yel_volcano_noOutlier,
       filename = "plots and figures/volcano plots/yel_volcano_noOutlier.svg")

# save interactive volcano plot
saveWidget(widget = yel_volcano_ggplotly_noOutlier,
           file = "plots and figures/volcano plots/interactive_yel_volcano_plot_noOutlier.html")

Joined lists

Here, I want to venn significant features before I begin to look more into them. I am interested in the following effects: tomato effect, lycopene and/or soy isoflavones effect.

Tomato effect

  1. Tomato effect: join a list that only keeps features that are both significant in pre vs. post-red and pre vs. post-yellow.
# keep only features present in both pre vs post red and pre vs post yellow
tomato_effect <- inner_join(red_sig_prepost_comp_clusters,
                            yel_sig_prepost_comp_clusters,
                            by = "mz_rt")
dim(tomato_effect)
## [1]  3 25

Export venned list

write_csv(tomato_effect,
          "Feature lists/sig-features-tomato-effect.csv")

Boxplots

all sig tomato features
# add in Feature ID annotations
anno_tomato_effect <- left_join(tomato_effect, df_for_stats_noOutlier, by = "mz_rt")

# metabs with pval < 0.05 and fc >= 1.51
sigmetabs_tomato_effect <- anno_tomato_effect$Feature_ID
tomato_effect_df_for_stats_wide <- df_for_stats_noOutlier_wide %>%
  dplyr::select(c(1:11),
                all_of(sigmetabs_tomato_effect))

# make tidy df
tomato_effect_df_for_stats_tidy <- tomato_effect_df_for_stats_wide %>%
  pivot_longer(cols = 12:ncol(.),
               names_to = "mz_rt",
               values_to = "rel_abund_log2")
# changing factor levels for pre_post_intervention
tomato_effect_df_for_stats_tidy$pre_post_intervention <- factor(tomato_effect_df_for_stats_tidy$pre_post_intervention,
                              levels = c("pre_Yellow", "post_Yellow", "pre_Red", "post_Red"))

levels(tomato_effect_df_for_stats_tidy$pre_post_intervention)  
## [1] "pre_Yellow"  "post_Yellow" "pre_Red"     "post_Red"
tomato_effect_df_for_stats_tidy %>% 
  ggplot(aes(x = pre_post_intervention, y = rel_abund_log2, fill = Intervention)) +
  geom_boxplot(outlier.shape = NA) +
  scale_fill_manual(values = c("Yellow" = "gold",
                                           "Red" = "tomato1")) +
  geom_line(aes(group = Subject), fill = "brown", linewidth = 0.2) +
  facet_wrap(vars(mz_rt), scales = "free_y") + 
  theme_clean() 

Let’s make them prettier.

my_comparisons <- list( c("pre_Yellow", "post_Yellow"), c("pre_Red", "post_Red") )

(bps_tomatoeffect_metabs <- tomato_effect_df_for_stats_tidy %>% 
  ggpaired(x = "pre_post_intervention", y = "rel_abund_log2", 
           fill = "Intervention", line.color = "gray",
           id = "Subject", line.size = 0.15) +
  scale_fill_manual(values = c("Red" = "tomato1",
                               "Yellow" = "yellow1"),
                    labels = c("Tomato-Soy", "Control")) +
  geom_point() +
  scale_x_discrete(labels = c("pre", "post", "pre", "post")) +
  labs(x = "",
       y = "Log2 relative abundance",
       title = "") +
  facet_wrap( ~ mz_rt, ncol = 3, labeller = labeller(mz_rt = label_wrap_gen(13))) +
  stat_compare_means(comparisons = my_comparisons, method = "t.test", paired = TRUE, p.adjust.method = "BH", label = "p.signif") +
  theme_classic(base_size = 14, base_family = "sans") +
  theme(axis.text.x = element_text(angle = 0)))

ggsave("plots and figures/bps_tomato_effect.svg")

Lyc/soy effect

  1. lycopene and/or soy isoflavones effect: join a list that only keeps features that are:
  • significantly different between post-Red and post-Yellow
  • and significant between pre- and post-Red.
# combine sig features from post-red vs post-yellow comparison
sig_postintervention_noOutlier <- full_join(postRed_sig_intrvntn_comp_clusters,
                                            postYellow_sig_intrvntn_comp_clusters)
dim(sig_postintervention_noOutlier)
## [1] 27 13
# select only sig features that are present when comparing pre-Red to post-Red
lyc_soy_effect <- inner_join(sig_postintervention_noOutlier,
                             red_sig_prepost_comp_clusters,
                             by = "mz_rt") 
dim(lyc_soy_effect)
## [1] 22 25

Export venned list

write_csv(lyc_soy_effect,
          "Feature lists/sig-features-lyc-soy-effect.csv")

Boxplots

all sig tomato features
# add in Feature ID annotations
anno_lycsoy_effect <- left_join(lyc_soy_effect, df_for_stats_noOutlier, by = "mz_rt")

# metabs with pval < 0.05 and fc >= 1.51
sigmetabs_lycsoy_effect <- anno_lycsoy_effect$Feature_ID
lycsoy_effect_df_for_stats_wide <- df_for_stats_noOutlier_wide %>%
  dplyr::select(c(1:11),
                all_of(sigmetabs_lycsoy_effect))

# make tidy df
lycsoy_effect_df_for_stats_tidy <- lycsoy_effect_df_for_stats_wide %>%
  pivot_longer(cols = 12:ncol(.),
               names_to = "mz_rt",
               values_to = "rel_abund_log2")
# changing factor levels for pre_post_intervention
lycsoy_effect_df_for_stats_tidy$pre_post_intervention <- factor(lycsoy_effect_df_for_stats_tidy$pre_post_intervention,
                              levels = c("pre_Yellow", "post_Yellow", "pre_Red", "post_Red"))

levels(lycsoy_effect_df_for_stats_tidy$pre_post_intervention)  
## [1] "pre_Yellow"  "post_Yellow" "pre_Red"     "post_Red"
lycsoy_effect_df_for_stats_tidy %>% 
  ggplot(aes(x = pre_post_intervention, y = rel_abund_log2, fill = Intervention)) +
  geom_boxplot(outlier.shape = NA) +
  scale_fill_manual(values = c("Yellow" = "gold",
                                           "Red" = "tomato1")) +
  geom_line(aes(group = Subject), fill = "brown", linewidth = 0.2) +
  facet_wrap(vars(mz_rt), scales = "free_y") + 
  theme_clean() 

Low carotenoid tomato effect

  1. yellow tomato effect: use list that only keeps features that are both significant between pre and post-yellow, and also significant between post-Red and post-Yellow
# sig features from post-red vs post-yellow
dim(sig_postintervention_noOutlier)
## [1] 27 13
# select only sig features that are present when comparing pre-Yellow to post-Yellow
low_carot_tomato_effect <- inner_join(sig_postintervention_noOutlier,
                             yel_sig_prepost_comp_clusters,
                             by = "mz_rt") 
dim(low_carot_tomato_effect)
## [1]  6 25

Export venned list

write_csv(low_carot_tomato_effect,
          "Feature lists/sig-features-low-carot-tomato-effect.csv")

Boxplots

all sig yellow tom features
# add in Feature ID annotations
anno_lowcarot_effect <- left_join(low_carot_tomato_effect, df_for_stats_noOutlier, by = "mz_rt")

# metabs with pval < 0.05 and fc >= 1.51
sigmetabs_lowcarot_effect <- anno_lowcarot_effect$Feature_ID
yellow_effect_df_for_stats_wide <- df_for_stats_noOutlier_wide %>%
  dplyr::select(c(1:11),
                all_of(sigmetabs_lowcarot_effect))

# make tidy df
yellow_effect_df_for_stats_tidy <- yellow_effect_df_for_stats_wide %>%
  pivot_longer(cols = 12:ncol(.),
               names_to = "mz_rt",
               values_to = "rel_abund_log2")
# changing factor levels for pre_post_intervention
yellow_effect_df_for_stats_tidy$pre_post_intervention <- factor(yellow_effect_df_for_stats_tidy$pre_post_intervention,
                              levels = c("pre_Yellow", "post_Yellow", "pre_Red", "post_Red"))

levels(yellow_effect_df_for_stats_tidy$pre_post_intervention)  
## [1] "pre_Yellow"  "post_Yellow" "pre_Red"     "post_Red"
yellow_effect_df_for_stats_tidy %>% 
  ggplot(aes(x = pre_post_intervention, y = rel_abund_log2, fill = Intervention)) +
  geom_boxplot(outlier.shape = NA) +
  scale_fill_manual(values = c("Yellow" = "gold",
                                           "Red" = "tomato1")) +
  geom_line(aes(group = Subject), fill = "brown", linewidth = 0.2) +
  facet_wrap(vars(mz_rt), scales = "free_y") + 
  theme_clean() 

LS0tCnRpdGxlOiAiVVNEQSBJbmZsYW1tYXRpb24gTWV0YWJvbG9taWNzIERhdGEgYW5hbHlzaXMiCnN1YnRpdGxlOiAiVXJpbmUsIEMxOCAoKykgTENNUyIKYXV0aG9yOiAiTWFyaWEgU2hvbG9sYSIKZGF0ZTogJzYvNS8yMDIzIGFuZCBzbyBvbicKb3V0cHV0OiAKICBodG1sX2RvY3VtZW50OgogICAgaGlnaGxpZ2h0OiBrYXRlCiAgICB0aGVtZTogeWV0aQogICAgdG9jOiB0cnVlCiAgICB0b2NfZmxvYXQ6IHRydWUKICAgIHRvY19kZXB0aDogNQogICAgY29kZV9kb3dubG9hZDogdHJ1ZQogICAgZmlnX3dpZHRoOiA3CmVkaXRvcl9vcHRpb25zOiAKICBjaHVua19vdXRwdXRfdHlwZTogaW5saW5lCi0tLQoKYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9IAprbml0cjo6b3B0c19jaHVuayRzZXQod2FybmluZyA9IEZBTFNFLCBtZXNzYWdlID0gRkFMU0UsIGVjaG89VFJVRSkgCmBgYAoKIyBMb2FkIGxpYnJhcmllcwpgYGB7ciwgd2FybmluZyA9IEZBTFNFLCBtZXNzYWdlID0gRkFMU0V9CmxpYnJhcnkocmVhZHhsKSAjIGZvciByZWFkaW5nIGluIGV4Y2VsIGZpbGVzCmxpYnJhcnkoamFuaXRvcikgIyBkYXRhIGNoZWNrcyBhbmQgY2xlYW5pbmcKbGlicmFyeShnbHVlKSAjIGZvciBlYXN5IHBhc3RpbmcKbGlicmFyeShGYWN0b01pbmVSKSAjIGZvciBQQ0EKbGlicmFyeShmYWN0b2V4dHJhKSAjIGZvciBQQ0EKbGlicmFyeShyc3RhdGl4KSAjIGZvciBzdGF0cwpsaWJyYXJ5KHBoZWF0bWFwKSAjIGZvciBoZWF0bWFwcwpsaWJyYXJ5KHBsb3RseSkgIyBmb3IgaW50ZXJhY3RpdmUgcGxvdHMKbGlicmFyeShodG1sd2lkZ2V0cykgIyBmb3Igc2F2aW5nIGludGVyYWN0aXZlIHBsb3RzCmxpYnJhcnkoZGV2dG9vbHMpCmxpYnJhcnkobm90YW1lKSAjIHVzZWQgZm9yIGZlYXR1cmUgY2x1c3RlcmluZwpsaWJyYXJ5KGRvUGFyYWxsZWwpCmxpYnJhcnkoaWdyYXBoKSAjIGZlYXR1cmUgY2x1c3RlcmluZwpsaWJyYXJ5KGdncHVicikgIyB2aXN1YWxpemF0aW9ucwpsaWJyYXJ5KGtuaXRyKSAjIGNsZWFuIHRhYmxlIHByaW50aW5nCmxpYnJhcnkobWl4T21pY3MpICMgZm9yIG11bHRpbGV2ZWwgUENBcwpsaWJyYXJ5KGdndGhlbWVzKQpsaWJyYXJ5KHBhdGh2aWV3KSAjIGZvciBmdW5jdGlvbmFsIGFuYWx5c2lzIGFuZCBLRUdHIGFubm90YXRpb24KbGlicmFyeShnZ2NvcnJwbG90KQpsaWJyYXJ5KGNvcnJyKQpsaWJyYXJ5KGdndGhlbWVzKQpsaWJyYXJ5KFBDQXRvb2xzKQpsaWJyYXJ5KHRpZHl2ZXJzZSkgIyBmb3IgZXZlcnl0aGluZwpgYGAKCiMgUmVhZCBpbiBkYXRhCmBgYHtyfQojIHJhdyBmaWx0ZXJlZCBtZXRhYm9sb21pY3MgZGF0YSBpbiBjMTggKCspCm9taWNzZGF0YSA8LSByZWFkX2NzdigiRmVhdHVyZSBsaXN0cy9jMThQb3MtRmlsdGVyZWQtRGF0YS0wNUp1bjIzXzk0NmZlYXR1cmVzLmNzdiIpCgojIG1ldGFkYXRhCm1ldGFkYXRhIDwtIHJlYWRfZXhjZWwoIk1ldGFkYXRhLXVyaW5lLWMxOHBvcy54bHN4IikKYGBgCgojIFdyYW5nbGUgZGF0YQoKYGBge3J9Cm1ldGFkYXRhIDwtIG1ldGFkYXRhICU+JQogIHJlbmFtZSgic2FtcGxlX0lEIiA9IFNhbXBsZV9JRCkKYGBgCgoKYGBge3J9CiMgcmVuYW1lICJyb3cgSUQiCm9taWNzZGF0YSA8LSBvbWljc2RhdGEgJT4lCiAgcmVuYW1lKCJyb3dfSUQiID0gYHJvdyBJRGApCgojIGhvdyBtYW55IGZlYXR1cmVzCm5yb3cob21pY3NkYXRhKQoKIyBhcmUgdGhlcmUgYW55IGR1cGxpY2F0ZXM/Cm9taWNzZGF0YSAlPiUgZ2V0X2R1cGVzKG16X3J0KQoKYGBgCgpSZW1vdmUgZHVwbGljYXRlcwpgYGB7cn0KIyByZW1vdmUgZHVwZXMKb21pY3NkYXRhIDwtIG9taWNzZGF0YSAlPiUgCiAgZGlzdGluY3QobXpfcnQsIC5rZWVwX2FsbCA9IFRSVUUpCgojIGNoZWNrIGFnYWluIGZvciBkdXBlcwpvbWljc2RhdGEgJT4lIGdldF9kdXBlcyhtel9ydCkKCiMgaG93IG1hbnkgZmVhdHVyZXMKbnJvdyhvbWljc2RhdGEpCmBgYAoKUmVtb3ZlIHdlaXJkIGVtcHR5IGNvbHVtbgpgYGB7cn0KY29sbmFtZXMob21pY3NkYXRhKQpgYGAKCgoKCmBgYHtyfQojIHJlbW92ZSB3ZWlyZCBsZ2wgY29sdW1uCm9taWNzZGF0YSA8LSBvbWljc2RhdGEgJT4lCiBkcGx5cjo6c2VsZWN0KCF3aGVyZShpcy5sb2dpY2FsKSkKCmNvbG5hbWVzKG9taWNzZGF0YSkKYGBgCgoKCmBgYHtyfQojIGNyZWF0ZSBsb25nIGRmIGZvciBvbWljcyBkZgpvbWljc2RhdGFfdGlkeSA8LSBvbWljc2RhdGEgJT4lCiAgcGl2b3RfbG9uZ2VyKGNvbHMgPSAzOm5jb2woLiksCiAgICAgICAgICAgICAgIG5hbWVzX3RvID0gInNhbXBsZV9JRCIsCiAgICAgICAgICAgICAgIHZhbHVlc190byA9ICJwZWFrX2hlaWdodCIpCgojIGNvbWJpbmUgbWV0YSBhbmQgb21pY3MgZGZzCmRmX2NvbWJpbmVkIDwtIGZ1bGxfam9pbihvbWljc2RhdGFfdGlkeSwKICAgICAgICAgICAgICAgICAgICAgICAgIG1ldGFkYXRhLAogICAgICAgICAgICAgICAgICAgICAgICAgYnkgPSBjKCJzYW1wbGVfSUQiID0gInNhbXBsZV9JRCIpKQoKIyBzZXBhcmF0ZSBteiBhbmQgcnQKZGZfY29tYmluZWRfc2VwIDwtIGRmX2NvbWJpbmVkICU+JQogIHNlcGFyYXRlKGNvbCA9IG16X3J0LAogICAgICAgICAgIGludG8gPSBjKCJteiIsICJydCIpLAogICAgICAgICAgIHNlcCA9ICJfIikgCgojIGNvbnZlcnQgY29sdW1ucyB0byBjb3JyZWN0IHR5cGUKZGZfY29tYmluZWRfc2VwJG16IDwtIGFzLm51bWVyaWMoZGZfY29tYmluZWRfc2VwJG16KQpkZl9jb21iaW5lZF9zZXAkcnQgPC0gYXMubnVtZXJpYyhkZl9jb21iaW5lZF9zZXAkcnQpCmRmX2NvbWJpbmVkX3NlcCRTdWJqZWN0IDwtIGFzLmNoYXJhY3RlcihkZl9jb21iaW5lZF9zZXAkU3ViamVjdCkKZGZfY29tYmluZWRfc2VwJEludGVydmVudGlvbiA8LSBhcy5jaGFyYWN0ZXIoZGZfY29tYmluZWRfc2VwJEludGVydmVudGlvbikKCiMgcmVhcnJhbmdlIGNvbHVtbiBvcmRlcgpkZl9jb21iaW5lZF9zZXAgPC0gZGZfY29tYmluZWRfc2VwICU+JQogZHBseXI6OnNlbGVjdChzYW1wbGVfSUQsIHByZV9wb3N0LCBJbnRlcnZlbnRpb24sIGV2ZXJ5dGhpbmcoKSkKCnN0cihkZl9jb21iaW5lZF9zZXApCgojIHJlcGxhY2UgTkEncyBpbiBzdWJqZWN0IGFuZCBpbnRlcnZlbnRpb24gY29sdW1ucyB3aXRoIFFDCmRmX2NvbWJpbmVkX3NlcCRTdWJqZWN0IDwtIGRmX2NvbWJpbmVkX3NlcCRTdWJqZWN0ICU+JQogIHJlcGxhY2VfbmEoIlFDIikKCmRmX2NvbWJpbmVkX3NlcCRJbnRlcnZlbnRpb24gPC0gZGZfY29tYmluZWRfc2VwJEludGVydmVudGlvbiAlPiUKICByZXBsYWNlX25hKCJRQyIpCgoKYGBgCgojIERhdGEgc3VtbWFyaWVzCgojIyBOdW1iZXIgb2YgbWFzc2VzIGRldGVjdGVkCmBgYHtyfQpucm93KG9taWNzZGF0YSkKYGBgCgoKIyMgTWFzcyByYW5nZSBmb3IgbWV0YWJvbGl0ZXMgZGV0ZWN0ZWQ/CgpgYGB7cn0KcmFuZ2UoZGZfY29tYmluZWRfc2VwJG16KQpgYGAKCiMjIFJUIHJhbmdlIGZvciBtZXRhYm9saXRlcyBkZXRlY3RlZD8KCmBgYHtyfQpyYW5nZShkZl9jb21iaW5lZF9zZXAkcnQpCmBgYAoKIyMgbWFzcyB2cyBSVCBzY2F0dGVycGxvdApgYGB7cn0KIyBwbG90CihwbG90X216dnNydCA8LSBkZl9jb21iaW5lZF9zZXAgJT4lCiAgZ2dwbG90KGFlcyh4ID0gcnQsIHkgPSBteikpICsKICBnZW9tX3BvaW50KCkgKwogIHRoZW1lX21pbmltYWwoKSArCiAgbGFicyh4ID0gIlJldGVudGlvbiB0aW1lLCBtaW4iLAogICAgICAgeSA9ICJtL3osIG5ldXRyYWwiLAogICAgICAgdGl0bGUgPSAibXogYWNyb3NzIFJUIGZvciBhbGwgZmVhdHVyZXMiKSkKYGBgCgojIyBIaXN0b2dyYW0gZm9yIG1hc3MgcmFuZ2UKYGBge3J9CmRmX2NvbWJpbmVkX3NlcCAlPiUKICBnZ3Bsb3QoYWVzKHggPSBteikpICsKICBnZW9tX2hpc3RvZ3JhbShiaW53aWR0aCA9IDI1KSArCiAgdGhlbWVfbWluaW1hbCgpICsKICBsYWJzKHggPSAiTW9ub2lzb3RvcGljIG1hc3MgKGFtdSkiLAogICAgICAgeSA9ICJOdW1iZXIgb2YgZmVhdHVyZXMiLAogICAgICAgdGl0bGUgPSAiRGlzdHJpYnV0aW9uIG9mIGZlYXR1cmVzIGJ5IG1hc3MiKQpgYGAKCiMjIEhpc3RvZ3JhbSBmb3IgUlQKCmBgYHtyfQpkZl9jb21iaW5lZF9zZXAgJT4lCiAgZ2dwbG90KGFlcyh4ID0gcnQpKSArCiAgZ2VvbV9oaXN0b2dyYW0oYmlud2lkdGggPSAwLjEpICsgIyA2IHNlY29uZCBiaW5zCiAgdGhlbWVfbWluaW1hbCgpICsKICBsYWJzKHggPSAiUmV0ZW50aW9uIHRpbWUiLAogICAgICAgeSA9ICJOdW1iZXIgb2YgZmVhdHVyZXMiLAogICAgICAgdGl0bGUgPSAiRGlzdHJpYnV0aW9uIG9mIGZlYXR1cmVzIGJ5IHJldGVudGlvbiB0aW1lIikKYGBgCgoKIyBOQXMgYW5kIGltcHV0aW5nCgojIyBOQXMKYGBge3J9CiMgTkFzIGluIGFsbCBkYXRhIGluY2x1ZGluZyBRQ3MKTkFieVJvdyA8LSByb3dTdW1zKGlzLm5hKG9taWNzZGF0YVssLTFdKSkKCmhpc3QoTkFieVJvdywKICAgICBicmVha3MgPSA1NiwgIyBiZWNhdXNlIHRoZXJlIGFyZSA1NiBzYW1wbGVzLCA0OCBzYW1wbGVzICsgOCBRQ3MKICAgICB4bGFiID0gIk51bWJlciBvZiBtaXNzaW5nIHZhbHVlcyIsCiAgICAgeWxhYiA9ICJOdW1iZXIgb2YgbWV0YWJvbGl0ZXMiLAogICAgIG1haW4gPSAiSG93IG1hbnkgbWlzc2luZyB2YWx1ZXMgYXJlIHRoZXJlPyIpCmBgYAoKYGBge3J9CiMgc2FtcGxlcyBvbmx5IChubyBRQ3MpCm9taWNzZGF0YV9ub1FDIDwtIG9taWNzZGF0YSAlPiUKIGRwbHlyOjpzZWxlY3QoLWNvbnRhaW5zKCJRQyIpKQoKI05BcyBpbiBzYW1wbGVzIG9ubHk/Ck5BYnlSb3dfbm9RQyA8LSByb3dTdW1zKGlzLm5hKG9taWNzZGF0YV9ub1FDWywtMV0pKQoKaGlzdChOQWJ5Um93X25vUUMsCiAgICAgYnJlYWtzID0gNDgsICMgYmVjYXVzZSB0aGVyZSBhcmUgNDggc2FtcGxlcyAKICAgICB4bGFiID0gIk51bWJlciBvZiBtaXNzaW5nIHZhbHVlcyIsCiAgICAgeWxhYiA9ICJOdW1iZXIgb2YgbWV0YWJvbGl0ZXMiLAogICAgIG1haW4gPSAiSG93IG1hbnkgbWlzc2luZyB2YWx1ZXMgYXJlIHRoZXJlPyIpCmBgYAoKQXJlIHRoZXJlIGFueSBtaXNzaW5nIHZhbHVlcyBpbiBRQ3M/IFRoZXJlIHNob3VsZG4ndCBiZSBhZnRlciBkYXRhIHByZXByb2Nlc3NpbmcvZmlsdGVyaW5nCmBgYHtyfQpvbWljc2RhdGFfUUMgPC0gb21pY3NkYXRhICU+JQogZHBseXI6OnNlbGVjdChzdGFydHNfd2l0aCgiUCIpKSAKCk5BYnlSb3dfUUMgPC0gY29sU3Vtcyhpcy5uYShvbWljc2RhdGFfUUMpKQojIGxldHMgY29uZmlybSB0aGF0IHRoZXJlIGFyZSBubyBtaXNzaW5nIHZhbHVlcyBmcm9tIG15IFFDcwpzdW0oTkFieVJvd19RQykgIyBubwpgYGAKCgpgYGB7cn0KIyBjYWxjdWxhdGUgaG93IG1hbnkgTkFzIHRoZXJlIGFyZSBwZXIgZmVhdHVyZSBpbiB3aG9sZSBkYXRhIHNldApjb250YWluc19OQXMgPC0gZGZfY29tYmluZWQgJT4lCiAgZ3JvdXBfYnkobXpfcnQpICU+JQogIGNvdW50KGlzLm5hKHBlYWtfaGVpZ2h0KSkgJT4lCiAgZmlsdGVyKGBpcy5uYShwZWFrX2hlaWdodClgID09IFRSVUUpCmhlYWQoY29udGFpbnNfTkFzKQpgYGAKCk5BcyBieSBncm91cHMKYGBge3J9CiNjYWxjdWxhdGUgTkFzIHBlciBmZWF0dXJlIGluIHJlZCBpbnRlcnZlbnRpb24KTkFzX1JlZF9JbnRlcnZlbnRpb24gPC0gZGZfY29tYmluZWQgJT4lCiAgZ3JvdXBfYnkobXpfcnQpICU+JQogIGZpbHRlcihJbnRlcnZlbnRpb24gPT0gIlJlZCIpICU+JQogIGNvdW50KGlzLm5hKHBlYWtfaGVpZ2h0KSkgJT4lCiAgZmlsdGVyKGBpcy5uYShwZWFrX2hlaWdodClgID09IFRSVUUpCgpoZWFkKE5Bc19SZWRfSW50ZXJ2ZW50aW9uKQoKI2NhbGN1bGF0ZSBOQXMgcGVyIGZlYXR1cmUgaW4geWVsbG93IGludGVydmVudGlvbgpOQXNfWWVsbG93X0ludGVydmVudGlvbiA8LSBkZl9jb21iaW5lZCAlPiUKICBncm91cF9ieShtel9ydCkgJT4lCiAgZmlsdGVyKEludGVydmVudGlvbiA9PSAiWWVsbG93IikgJT4lCiAgY291bnQoaXMubmEocGVha19oZWlnaHQpKSAlPiUKICBmaWx0ZXIoYGlzLm5hKHBlYWtfaGVpZ2h0KWAgPT0gVFJVRSkKCmhlYWQoTkFzX1llbGxvd19JbnRlcnZlbnRpb24pCiNjYWxjdWxhdGUgTkFzIHBlciBmZWF0dXJlIGluIGJlZm9yZSBib3RoIGludGVydmVudGlvbnMKTkFzX3ByZUludGVydmVudGlvbiA8LSBkZl9jb21iaW5lZCAlPiUKICBncm91cF9ieShtel9ydCkgJT4lCiAgZmlsdGVyKHByZV9wb3N0ID09ICJwcmUiKSAlPiUKICBjb3VudChpcy5uYShwZWFrX2hlaWdodCkpICU+JQogIGZpbHRlcihgaXMubmEocGVha19oZWlnaHQpYCA9PSBUUlVFKQoKaGVhZChOQXNfcHJlSW50ZXJ2ZW50aW9uKQojY2FsY3VsYXRlIE5BcyBwZXIgZmVhdHVyZSBhZnRlciBib3RoIGludGVydmVudGlvbnMKTkFzX3Bvc3RJbnRlcnZlbnRpb24gPC0gZGZfY29tYmluZWQgJT4lCiAgZ3JvdXBfYnkobXpfcnQpICU+JQogIGZpbHRlcihwcmVfcG9zdCA9PSAicG9zdCIpICU+JQogIGNvdW50KGlzLm5hKHBlYWtfaGVpZ2h0KSkgJT4lCiAgZmlsdGVyKGBpcy5uYShwZWFrX2hlaWdodClgID09IFRSVUUpCgpoZWFkKE5Bc19wb3N0SW50ZXJ2ZW50aW9uKQpgYGAKCgoKIyMgRGF0YSBpbXB1dGF0aW9uCmBgYHtyfQojIGltcHV0ZSBhbnkgbWlzc2luZyB2YWx1ZXMgYnkgcmVwbGFjaW5nIHRoZW0gd2l0aCAxLzIgb2YgdGhlIGxvd2VzdCBwZWFrIGhlaWdodCB2YWx1ZSBvZiBhIGZlYXR1cmUgKGkuZS4gaW4gYSByb3cpLgppbXB1dGVkX29taWNzZGF0YSA8LSBvbWljc2RhdGEKCmltcHV0ZWRfb21pY3NkYXRhW10gPC0gbGFwcGx5KGltcHV0ZWRfb21pY3NkYXRhLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZnVuY3Rpb24oeCkgaWZlbHNlKGlzLm5hKHgpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWluKHgsIG5hLnJtID0gVFJVRSkvMiwgeCkpCgpkaW0oaW1wdXRlZF9vbWljc2RhdGEpCmBgYAoKQXJlIHRoZXJlIGFueSBOQXM/CmBgYHtyfQppbXB1dGVkX29taWNzZGF0YSAlPiUKICBpcy5uYSgpICU+JQogIHN1bSgpCgojIGltcHV0YXRpb25zIHdvcmtlZApgYGAKCgojIENyZWF0ZSBuZXcgaW1wdXRlZCB0aWR5IGRhdGFzZXRzCmBgYHtyfQojIGNyZWF0ZSBsb25nIGRmIGZvciBpbXB1dGVkIG9taWNzIGRmCmltcHV0ZWRfb21pY3NkYXRhX3RpZHkgPC0gaW1wdXRlZF9vbWljc2RhdGEgJT4lCiAgcGl2b3RfbG9uZ2VyKGNvbHMgPSAzOm5jb2woLiksCiAgICAgICAgICAgICAgIG5hbWVzX3RvID0gInNhbXBsZV9JRCIsCiAgICAgICAgICAgICAgIHZhbHVlc190byA9ICJwZWFrX2hlaWdodCIpCgojIGNvbWJpbmUgbWV0YSBhbmQgaW1wdXRlZCBvbWljcyBkZnMKaW1wdXRlZF9mdWxsZGF0YSA8LSBmdWxsX2pvaW4oaW1wdXRlZF9vbWljc2RhdGFfdGlkeSwKICAgICAgICAgICAgICAgICAgICAgICAgIG1ldGFkYXRhLAogICAgICAgICAgICAgICAgICAgICAgICAgYnkgPSBjKCJzYW1wbGVfSUQiID0gInNhbXBsZV9JRCIpKQoKIyBzZXBhcmF0ZSBteiBhbmQgcnQKaW1wdXRlZF9mdWxsZGF0YV9zZXAgPC0gaW1wdXRlZF9mdWxsZGF0YSAlPiUKICBzZXBhcmF0ZShjb2wgPSBtel9ydCwKICAgICAgICAgICBpbnRvID0gYygibXoiLCAicnQiKSwKICAgICAgICAgICBzZXAgPSAiXyIpIAoKIyBjb252ZXJ0IGNvbHVtbnMgdG8gY29ycmVjdCB0eXBlCmltcHV0ZWRfZnVsbGRhdGFfc2VwJG16IDwtIGFzLm51bWVyaWMoaW1wdXRlZF9mdWxsZGF0YV9zZXAkbXopCmltcHV0ZWRfZnVsbGRhdGFfc2VwJHJ0IDwtIGFzLm51bWVyaWMoaW1wdXRlZF9mdWxsZGF0YV9zZXAkcnQpCmltcHV0ZWRfZnVsbGRhdGFfc2VwJFN1YmplY3QgPC0gYXMuY2hhcmFjdGVyKGltcHV0ZWRfZnVsbGRhdGFfc2VwJFN1YmplY3QpCmltcHV0ZWRfZnVsbGRhdGFfc2VwJEludGVydmVudGlvbiA8LSBhcy5jaGFyYWN0ZXIoaW1wdXRlZF9mdWxsZGF0YV9zZXAkSW50ZXJ2ZW50aW9uKQpgYGAKCiMjIFBsb3QgZmVhdHVyZXMuIFJUIHZzIG16CmBgYHtyfQojIHJ0IHZzIG16IHBsb3QKaW1wdXRlZF9mdWxsZGF0YV9zZXAgJT4lCiAgZ2dwbG90KGFlcyh4ID0gcnQsIHkgPSBteikpICsKICBnZW9tX3BvaW50KCkgKwogIHRoZW1lX21pbmltYWwoKSArCiAgbGFicyh4ID0gIlJUIChtaW4pIiwKICAgICAgIHkgPSAibXoiKQpgYGAKCiMgTm90YW1lIGZlYXR1cmUgcmVkdWN0aW9uCnZpZ25ldHRlIGZvciByZWZlcmVuY2UKYGBge3J9CiNicm93c2VWaWduZXR0ZXMoIm5vdGFtZSIpCmBgYAoKIyMgRGF0YSByZXN0cnVjdHVyaW5nIGZvciBub3RhbWUKCgpgYGB7cn0KIyBjcmVhdGUgZmVhdHVyZXMgbGlzdCBmcm9tIGltcHV0ZWQgZGF0YSBzZXQgdG8gb25seSBpbmNsdWRlIHVuaXF1ZSBmZWF0dXJlIElEJ3MgKG16X3J0KSwgbXogYW5kIFJUCmZlYXR1cmVzIDwtIGltcHV0ZWRfZnVsbGRhdGFfc2VwICU+JQogIGNiaW5kKGltcHV0ZWRfZnVsbGRhdGEkbXpfcnQpICU+JQogIHJlbmFtZSgibXpfcnQiID0gImltcHV0ZWRfZnVsbGRhdGEkbXpfcnQiKSAlPiUKIGRwbHlyOjpzZWxlY3QoYyhtel9ydCwgbXosIHJ0KSkgJT4lCiAgZGlzdGluY3QoKSAjIHJlbW92ZSB0aGUgZHVwbGljYXRlIHJvd3MKCiMgY3JlYXRlIGEgc2Vjb25kIGRhdGEgZnJhbWUgd2hpY2ggaXMganVzdCBpbXB1dGVkX2Z1bGxkYXRhIHJlc3RydWN0dXJlZCB0byBhbm90aGVyIHdpZGUgZm9ybWF0CmRhdGFfbm90YW1lIDwtIGRhdGEuZnJhbWUoaW1wdXRlZF9vbWljc2RhdGEgJT4lCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGRwbHlyOjpzZWxlY3QoLXJvd19JRCkgJT4lCiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0KCkpCgpkYXRhX25vdGFtZSA8LSBkYXRhX25vdGFtZSAlPiUKICB0aWJibGU6OnJvd25hbWVzX3RvX2NvbHVtbigpICU+JSAjIGNoYW5nZSBzYW1wbGVzIGZyb20gcm93bmFtZXMgdG8gaXRzIG93biBjb2x1bW4KICByb3dfdG9fbmFtZXMocm93X251bWJlciA9IDEpICMgY2hhbmdlIHRoZSBmZWF0dXJlIElEcyAobXpfcnQpIGZyb20gZmlyc3Qgcm93IG9icyBpbnRvIGNvbHVtbiBuYW1lcwoKCmBgYAoKQ2hlY2sgc3RydWN0dXJlcwpgYGB7cn0KIyBjaGVjayBpZiBteiBhbmQgcnQgYXJlIG51bWVyaWMKc3RyKGZlYXR1cmVzKQp0aWJibGUoZmVhdHVyZXMpCmBgYAoKYGBge3J9CiMgY2hlY2sgaWYgcmVzdWx0cyBhcmUgbnVtZXJpYwp0aWJibGUoZGF0YV9ub3RhbWUpCgojIGNoYW5nZSB0byByZXN1bHRzIHRvIG51bWVyaWMKZGF0YV9ub3RhbWUgPC0gZGF0YV9ub3RhbWUgJT4lCiAgbXV0YXRlX2F0KC0xLCBhcy5udW1lcmljKQoKdGliYmxlKGRhdGFfbm90YW1lKQpgYGAKCgojIyBGaW5kIGNvbm5lY3Rpb25zCmBgYHtyfQpjb25uZWN0aW9uIDwtIGZpbmRfY29ubmVjdGlvbnMoZGF0YSA9IGRhdGFfbm90YW1lLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmVhdHVyZXMgPSBmZWF0dXJlcywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvcnJfdGhyZXNoID0gMC45LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcnRfd2luZG93ID0gMS82MCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5hbWVfY29sID0gIm16X3J0IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG16X2NvbCA9ICJteiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBydF9jb2wgPSAicnQiKQoKaGVhZChjb25uZWN0aW9uKQpgYGAKCiMjIENsdXN0ZXJpbmcKYGBge3J9CmNsdXN0ZXJzIDwtIGZpbmRfY2x1c3RlcnMoY29ubmVjdGlvbnMgPSBjb25uZWN0aW9uLCBkX3RocmVzaCA9IDAuOCkKYGBgCgpgYGB7cn0KIyBhc3NpZ24gYSBjbHVzdGVyIElEIHRvIGFsbCBmZWF0dXJlcy4gQ2x1c3RlcnMgYXJlIG5hbWVkIGFmdGVyIGZlYXR1cmUgd2l0aCBoaWdoZXN0IG1lZGlhbiBwZWFrIGhlaWdodApmZWF0dXJlc19jbHVzdGVyZWQgPC0gYXNzaWduX2NsdXN0ZXJfaWQoZGF0YV9ub3RhbWUsIGNsdXN0ZXJzLCBmZWF0dXJlcywgbmFtZV9jb2wgPSAibXpfcnQiKQoKIyB2aXN1YWxpemUgY2x1c3RlcnMKI3Zpc3VhbGl6ZV9jbHVzdGVycyhkYXRhX25vdGFtZSwgZmVhdHVyZXMsIGNsdXN0ZXJzLCBtaW5fc2l6ZSA9IDMsIHJ0X3dpbmRvdyA9IDIsbmFtZV9jb2wgPSAibXpfcnQiLCBtel9jb2wgPSAibXoiLCBydF9jb2wgPSAicnQiLCBmaWxlX3BhdGggPSAifi9wYXRoL3RvL3Byb2plY3QvIikKCiMgbGV0cyBzZWUgaG93IG1hbnkgZmVhdHVyZXMgYXJlIHJlbW92ZWQgd2hlbiB3ZSBvbmx5IGtlZXAgb25lIGZlYXR1cmUgcGVyIGNsdXN0ZXIKcHVsbGVkIDwtIHB1bGxfY2x1c3RlcnMoZGF0YV9ub3RhbWUsIGZlYXR1cmVzX2NsdXN0ZXJlZCwgbmFtZV9jb2wgPSAibXpfcnQiKQpjbHVzdGVyX2RhdGEgPC0gcHVsbGVkJGNkYXRhCmNsdXN0ZXJfZmVhdHVyZXMgPC0gcHVsbGVkJGNmZWF0dXJlcwojIGV4cG9ydCBjbHVzdGVyZWQgZmVhdHVyZSBsaXN0CndyaXRlX2NzdihjbHVzdGVyX2ZlYXR1cmVzLAogICAgICAgICAgIm5vdGFtZV9kZnMvY2x1c3Rlcl9mZWF0dXJlcy1fYzE4LXBvcy5jc3YiKQoKbnJvdyhvbWljc2RhdGEpIC0gbnJvdyhjbHVzdGVyX2ZlYXR1cmVzKQpgYGAKCiMjIFJlZHVjZSBkYXRhc2V0IGJhc2VkIG9uIGNsdXN0ZXJpbmcKCmBgYHtyfQojIHRyYW5zcG9zZSB0aGUgZnVsbCBkYXRhc2V0IGJhY2sgdG8gd2lkZSBzbyB0aGF0IGl0IGlzIG1vcmUgc2ltaWxhciB0byB0aGUgbm90YW1lIGRhdGFzZXQKaW1wdXRlZF9mdWxsZGF0YV93aWRlIDwtIGltcHV0ZWRfZnVsbGRhdGEgJT4lCiBkcGx5cjo6c2VsZWN0KC0icm93X0lEIikgJT4lCiAgcGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9IG16X3J0LAogICAgICAgICAgICAgIHZhbHVlc19mcm9tID0gcGVha19oZWlnaHQpCgojIGxpc3Qgb2YgcmVkdWNlZCBmZWF0dXJlcwpjbHVzdGVybmFtZXMgPC0gY2x1c3Rlcl9mZWF0dXJlcyRtel9ydAoKI2RwbHlyOjogb25seSB0aGUgZmVhdHVyZXMgYXJlIGluIHRoZSByZWR1Y2VkIGxpc3QKaW1wX2NsdXN0IDwtIGltcHV0ZWRfZnVsbGRhdGFfd2lkZVssYyhuYW1lcyhpbXB1dGVkX2Z1bGxkYXRhX3dpZGUpICVpbiUgY2x1c3Rlcm5hbWVzKV0KCiMgYmluZCBiYWNrIHNhbXBsZSBuYW1lcwppbXBfY2x1c3QgPC0gY2JpbmQoaW1wdXRlZF9mdWxsZGF0YV93aWRlWzFdLCBpbXBfY2x1c3QpCgpuY29sKGltcF9jbHVzdFssLTFdKQoKYGBgCgojIyBNeiB2cyBSVCBzY2F0dGVycGxvdCAKCmBgYHtyfQojIHBsb3QgbmV3IHJ0IHZzIG16IHNjYXR0ZXJwbG90IHBvc3QtY2x1c3RlcmluZwoocGxvdF9tenZzcnRfcG9zdGNsdXN0ZXIgPC0gY2x1c3Rlcl9mZWF0dXJlcyAlPiUKICBnZ3Bsb3QoYWVzKHggPSBydCwKICAgICAgICAgICAgIHkgPSBteikpICsKICBnZW9tX3BvaW50KCkgKwogIHRoZW1lX21pbmltYWwoKSArCiAgbGFicyh4ID0gIlJldGVudGlvbiB0aW1lLCBtaW4iLAogICAgICAgeSA9ICJtL3osIG5ldXRyYWwiLAogICAgICAgdGl0bGUgPSAibXogYWNyb3NzIFJUIGZvciBhbGwgZmVhdHVyZXMgYWZ0ZXIgY2x1c3RlcmluZyIpKQoKCmBgYAoKCmBgYHtyfQojIHBsb3QgYm90aCBzY2F0dGVycGxvdHMgdG8gY29tcGFyZSB3aXRoIGFuZCB3aXRob3V0IG5vdGFtZSBjbHVzdGVyaW5nCihzY2F0dGVycGxvdHMgPC0gZ2dhcnJhbmdlKHBsb3RfbXp2c3J0LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgcGxvdF9tenZzcnRfcG9zdGNsdXN0ZXIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICBucm93ID0gMikpCmBgYAoKIyBCaW5kIG1ldGEgZGF0YQpgYGB7cn0KaW1wX21ldGFiaW5kX2NsdXN0IDwtIHJpZ2h0X2pvaW4obWV0YWRhdGEsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpbXBfY2x1c3QsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJ5ID0gInNhbXBsZV9JRCIpCmBgYAoKIyBWaXN1YWxpemUgdW50cmFuc2Zvcm1lZCBkYXRhCgojIyBEYXRhIHdyYW5nbGluZwpgYGB7cn0KIyBjaGFuZ2UgbWV0YSBkYXRhIGNvbHVtbnMgdG8gY2hhcmFjdGVyIHNvIHRoYXQgSSBjYW4gY2hhbmdlIE5BcyBmcm9tIFFDcyB0byAiUUMiCmltcF9tZXRhYmluZF9jbHVzdCA8LSBpbXBfbWV0YWJpbmRfY2x1c3QgJT4lCiAgbXV0YXRlX2F0KGMoIlN1YmplY3QiLAogICAgICAgICAgICAgICJQZXJpb2QiLAogICAgICAgICAgICAgICJJbnRlcnZlbnRpb24iLAogICAgICAgICAgICAgICJwcmVfcG9zdCIsCiAgICAgICAgICAgICAgInNlcXVlbmNlIiwKICAgICAgICAgICAgICAiSW50ZXJ2ZW50aW9uX3dlZWsiLAogICAgICAgICAgICAgICJTZXgiLAogICAgICAgICAgICAgICJBZ2UiLAogICAgICAgICAgICAgICJCTUkiKSwKICAgICAgICAgICAgYXMuY2hhcmFjdGVyKSAKCiMgcmVwbGFjZSBOQXMgaW4gbWV0YWRhdGEgY29sdW1ucyBmb3IgUUNzCmltcF9tZXRhYmluZF9jbHVzdFtpcy5uYShpbXBfbWV0YWJpbmRfY2x1c3QpXSA8LSAiUUMiCgojIHVuaXRlIHByZV9wb3N0IGNvbHVtbiB3aXRoIGludGVydmVudGlvbiBjb2x1bW4gdG8gY3JlYXRlIHByZV9pbnRlcnZlbnRpb24gY29sdW1uCmltcF9tZXRhYmluZF9jbHVzdCA8LSBpbXBfbWV0YWJpbmRfY2x1c3QgJT4lCiAgdW5pdGUoY29sID0gInByZV9wb3N0X2ludGVydmVudGlvbiIsCiAgICAgICAgYygicHJlX3Bvc3QiLCJJbnRlcnZlbnRpb24iKSwKICAgICAgICBzZXAgPSAiXyIsCiAgICAgICAgcmVtb3ZlID0gRkFMU0UpCgojIGxvbmcgZGYKaW1wX21ldGFiaW5kX2NsdXN0X3RpZHkgPC0gaW1wX21ldGFiaW5kX2NsdXN0ICU+JQogIHBpdm90X2xvbmdlcihjb2xzID0gMTI6bmNvbCguKSwKICAgICAgICAgICAgICAgbmFtZXNfdG8gPSAibXpfcnQiLAogICAgICAgICAgICAgICB2YWx1ZXNfdG8gPSAicmVsX2FidW5kIikKCiMgc3RydWN0dXJlIGNoZWNrCnN0cihpbXBfbWV0YWJpbmRfY2x1c3RfdGlkeSkKYGBgCgoKCiMjIEJveHBsb3QKYGBge3J9CmltcF9tZXRhYmluZF9jbHVzdF90aWR5ICU+JQogIGdncGxvdChhZXMoeCA9IHNhbXBsZV9JRCwgeSA9IHJlbF9hYnVuZCwgY29sb3IgPSBJbnRlcnZlbnRpb24pKSArCiAgZ2VvbV9ib3hwbG90KGFscGhhID0gMC42KSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGMoImxpZ2h0IGdyZXkiLCAidG9tYXRvMSIsICJnb2xkIikpICsKICB0aGVtZV9taW5pbWFsKCkgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTApKSArCiAgbGFicyh0aXRsZSA9ICJMQy1NUyAoKykgRmVhdHVyZSBBYnVuZGFuY2VzIGJ5IFNhbXBsZSIsCiAgICAgICBzdWJ0aXRsZSA9ICJVbnNjYWxlZCBkYXRhIiwKICAgICAgIHkgPSAiUmVsYXRpdmUgYWJ1bmRhbmNlIikKYGBgCldpbGwgbmVlZCB0byBsb2cgdHJhbnNmb3JtIGluIG9yZGVyIHRvIG5vcm1hbGl6ZSBhbmQgYWN0dWFsbHkgc2VlIHRoZSBkYXRhCgojIExvZzIgdHJhbnNmb3JtCmBgYHtyfQppbXBfbWV0YWJpbmRfY2x1c3RfdGlkeV9sb2cyIDwtIGltcF9tZXRhYmluZF9jbHVzdF90aWR5ICU+JQogIG11dGF0ZShyZWxfYWJ1bmRfbG9nMiA9IGlmX2Vsc2UocmVsX2FidW5kID4gMCwgbG9nMihyZWxfYWJ1bmQpLCAwKSkgJT4lCiAgcmVwbGFjZShpcy5uYSguKSwgMCkKYGBgCgojIyBCb3hwbG90CmBgYHtyfQooYnBfZGF0YV9xdWFsaXR5IDwtIGltcF9tZXRhYmluZF9jbHVzdF90aWR5X2xvZzIgJT4lCiAgZ2dwbG90KGFlcyh4ID0gc2FtcGxlX0lELCB5ID0gcmVsX2FidW5kX2xvZzIsIGZpbGwgPSBJbnRlcnZlbnRpb24pKSArCiAgZ2VvbV9ib3hwbG90KGFscGhhID0gMC42KSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygibGlnaHQgZ3JleSIsICJ0b21hdG8xIiwgImdvbGQiKSkgKwogIHRoZW1lX21pbmltYWwoKSArCiAgbGFicyh0aXRsZSA9ICJMQy1NUyAoKykgRmVhdHVyZSBBYnVuZGFuY2VzIGJ5IFNhbXBsZSIsCiAgICAgICBzdWJ0aXRsZSA9ICJMb2cyIHRyYW5zZm9ybWVkIGRhdGEiLAogICAgICAgeSA9ICJSZWxhdGl2ZSBhYnVuZGFuY2UiKSkKYGBgCgoKIyBOb3RhbWUgZHJpZnQgY29ycmVjdGlvbgoKIyMgRGF0YSB3cmFuZ2xpbmcKCiMjIyBGZWF0dXJlIGFidW5kIGRmIAoKYGBge3J9CiMgZmlsdGVyZWQgYW5kIGltcHV0ZWQgZGF0YSBhZnRlciBub3RhbWUgY2x1c3RlcmluZywgdHJhbnNwb3NlZApmZWF0dXJlc190ZXN0Zm9yUUNjb3JyIDwtIHQoaW1wX2NsdXN0KSAlPiUKICBhcy5kYXRhLmZyYW1lKCkgJT4lCiAgcm93X3RvX25hbWVzKHJvd19udW1iZXIgPSAiZmluZF9oZWFkZXIiKQoKIyBsb2cyIHRyYW5zZm9ybQpsb2cyX2ZlYXR1cmVzX3Rlc3Rmb3JRQ2NvcnIgPC0gZmVhdHVyZXNfdGVzdGZvclFDY29yciAlPiUKICBtdXRhdGVfYWxsKGFzLm51bWVyaWMpICU+JQogIGxvZzIoKQoKIyB3cml0ZSBjc3YgdG8gbWFudWFsbHkgZWRpdAp3cml0ZS5jc3YobG9nMl9mZWF0dXJlc190ZXN0Zm9yUUNjb3JyLAogICAgICAgICAgIm5vdGFtZV9kZnMvZmVhdXJlc190ZXN0LmNzdiIsCiAgICAgICAgICByb3cubmFtZXMgPSBUUlVFKQpgYGAKCkltcG9ydCBjb3JyZWN0ZWQgZGYgKGVkaXRlZCBzbyB0aGF0IG16X3J0IGNvdWxkIHJvd25hbWUgMSkKYGBge3J9CiMgZm9yIHNvbWUgcmVhc29uIHRoZSByIGlzIG5vdCByZWNvZ25pemluZyBteSB3ZCBzbyBJJ2xsIHJ1biBmaWxlLmNob29zZQoKZmVhdHVyZXNfZm9yUUNjb3JyIDwtIHJlYWQuY3N2KCJub3RhbWVfZGZzL2ZlYXVyZXNfZm9yUUNjb3JyLmNzdiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaGVhZGVyID0gRkFMU0UsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcm93Lm5hbWVzID0gMSkKCgpmZWF0dXJlc19mb3JRQ2NvcnIgPC0gZmVhdHVyZXNfZm9yUUNjb3JyICU+JQogIHJvd25hbWVzX3RvX2NvbHVtbih2YXIgPSAibXpfcnQiKSAlPiUKICByb3dfdG9fbmFtZXMocm93X251bWJlciA9IDEpJT4lCiAgc2VwYXJhdGUoY29sID0gbXpfcnQsCiAgICAgICAgICAgaW50byA9IGMoIm16IiwgInJ0IiksCiAgICAgICAgICAgc2VwID0gIl8iKQoKd3JpdGUuY3N2KGZlYXR1cmVzX2ZvclFDY29yciwKICAgICAgICAgICJub3RhbWVfZGZzL2ZlYXR1cmVzX2ZvclFDY29ycl9wdDIuY3N2IiwKICAgICAgICAgIHJvdy5uYW1lcyA9IFRSVUUpCgpgYGAKCgojIyMgUGhlbm8gZGYKCmBgYHtyfQojIHNlcGFyYXRlIHNhbXBsZUlEIGFuZCBpbmplY3Rpb24gb3JkZXIKcGhlbm9fZGF0YSA8LSBpbXBfY2x1c3RbMV0gJT4lCiAgc2VwYXJhdGUoY29sID0gc2FtcGxlX0lELAogICAgICAgICAgIGludG8gPSBjKCJzYW1wbGVfSUQiLCAiaW5qZWN0aW9uX29yZGVyIiksCiAgICAgICAgICAgc2VwID0gIl9jMThQT1NfIikKCiMgZml4IGluamVjdGlvbiBudW1iZXJzIHRvIGNvcnJlY3QgbnVtYmVyCnBoZW5vX2RhdGFbNTQsICJpbmplY3Rpb25fb3JkZXIiXSA8LSA5CnBoZW5vX2RhdGFbNDAsICJpbmplY3Rpb25fb3JkZXIiXSA8LSAxMApwaGVub19kYXRhWzEzLCAiaW5qZWN0aW9uX29yZGVyIl0gPC0gMjYKcGhlbm9fZGF0YVsyNCwgImluamVjdGlvbl9vcmRlciJdIDwtIDI3CnBoZW5vX2RhdGFbNDIsICJpbmplY3Rpb25fb3JkZXIiXSA8LSAyOApwaGVub19kYXRhWzMyLCAiaW5qZWN0aW9uX29yZGVyIl0gPC0gMjkKCiMgbWFrZSBpbmogb3JkZXIgY29sdW1uIG51bWVyaWMKcGhlbm9fZGF0YSA8LSBwaGVub19kYXRhICU+JQogIG11dGF0ZV9hdCgiaW5qZWN0aW9uX29yZGVyIiwgYXMubnVtZXJpYykKCnRfcGhlbm9fZGF0YSA8LSBhcy5kYXRhLmZyYW1lKHQocGhlbm9fZGF0YSkpCgp3cml0ZS5jc3YodF9waGVub19kYXRhLAogICAgICAgICAgIm5vdGFtZV9kZnMvcGhlbm9fZGYuY3N2IiwKICAgICAgICAgIHJvdy5uYW1lcyA9IFRSVUUpCmBgYAoKQ29tYmluZSBwaGVubyBhbmQgZmVhdHVyZSBkZnMgbWFudWFsbHkgaW4gZXhjZWwgdG8gY3JlYXRlIG1ldGFib3NldCBkZi4KCiMjIEltcG9ydCBNZXRhYm9zZXQKCmBgYHtyfQoKI21ha2Ugc3VyZSB3aGVuIGNvbnZlcnRpbmcgY3N2IHRvIHhsc3ggdGhhdCB5b3Ugc2F2ZSBhcyBhIG5ldyBmaWxlLCBkb24ndCBqdXN0IGNoYW5nZSB0aGUgbmFtZSBvZiB0aGUgZmlsZQptZXRhYm9zZXQgPC0gcmVhZF9mcm9tX2V4Y2VsKCJub3RhbWVfZGZzL21ldGFib3NldC54bHN4IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzcGxpdF9ieSA9IGMoImNvbHVtbiIsICJJb24gbW9kZSIpKQoKYGBgCgoKYGBge3J9CiNjb25zdHJ1Y3QgTWV0YWJvc2V0Cm1vZGVzIDwtIGNvbnN0cnVjdF9tZXRhYm9zZXRzKGV4cHJzID0gbWV0YWJvc2V0JGV4cHJzLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwaGVub19kYXRhID0gbWV0YWJvc2V0JHBoZW5vX2RhdGEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZlYXR1cmVfZGF0YSA9IG1ldGFib3NldCRmZWF0dXJlX2RhdGEsIGdyb3VwX2NvbCA9ICJDbGFzcyIpCgojZXh0cmFjdCBlYWNoIG1vZGUgaW50byBhIHNpbmdsZSBvYmplY3QKbW9kZSA8LSBtb2RlcyRjMThfcG9zCmBgYAoKCiMjIEJveHBsb3RzIGJlZm9yZSBjb3JyZWN0aW9uCgpgYGB7ciwgZXZhbCA9IEZ9CiMgb3JkZXJlZCBieSBpbmplY3Rpb24KKHF1YWxpdHlCUHNfYjRjb3JyZWN0aW9uIDwtIHBsb3Rfc2FtcGxlX2JveHBsb3RzKG1vZGUsIG9yZGVyX2J5ID0gIkNsYXNzIiwgdGl0bGUgPSAiYzE4ICgrKSB1bmNvcnJlY3RlZCBmZWF0dXJlIGFidW5kYW5jZSIpICsKICAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygibGlnaHQgZ3JheSIsICJkZWVwc2t5Ymx1ZTIiKSkpCgojb3JkZXJlZCBieSBjbGFzcwpwbG90X3NhbXBsZV9ib3hwbG90cyhtb2RlLCBvcmRlcl9ieSA9ICJJbmplY3Rpb25fb3JkZXIiLCB0aXRsZSA9ICJVbmNvcnJlY3RlZCBmZWF0dXJlIGFidW5kYW5jZSIpICsKICAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygibGlnaHQgZ3JheSIsICJkZWVwc2t5Ymx1ZTIiKSkKYGBgCgoKIyMgQm94cGxvdHMgYWZ0ZXIgUUMgZHJpZnQgY29ycmVjdGlvbgoKZHJpZnQgY29ycmVjdGVkIHRha2VzIHVwIHRvIDIgbWludXRlcwpgYGB7ciwgZXZhbCA9IEZ9Cm1vZGUgPC0gZmxhZ19kZXRlY3Rpb24obW9kZSwgcWNfbGltaXQgPSAwLjc1LCBncm91cF9saW1pdCA9IDAuOCkKYGBgCgoKYGBge3IsIGV2YWwgPSBGfQpjb3JyZWN0ZWQgPC0gY29ycmVjdF9kcmlmdChtb2RlLCBsb2dfdHJhbnNmb3JtID0gRkFMU0UpCmBgYAoKCiMjIyBEaWQgZHJpZnQgY29ycmVjdGlvbiB3b3JrPwoKIG91dHB1dCBpcyBwZXJjZW50IG9mIHRoZSBmZWF0dXJlcyB0aGF0IHdlcmUgZHJpZnQgY29ycmVjdGVkLiBUaGUgcmVtYWluaW5nICJsb3ctcXVhbGl0eSIgcGVyY2VudCByZXByZXNlbnRzIGZlYXR1cmVzIGZvciB3aGljaCB0aGUgREMgZGlkICpub3QqIGltcHJvdmUgdGhlIFJTRCBhbmQgRC1yYXRpbyBvZiB0aGUgb3JpZ2luYWwgZGF0YS4KCmBgYHtyLCBldmFsID0gRn0KaW5zcGVjdGVkIDwtIGluc3BlY3RfZGMob3JpZyA9IG1vZGUsIGRjID0gY29ycmVjdGVkLCBjaGVja19xdWFsaXR5ID0gVFJVRSkKYGBgCgojIyMgQm94cGxvdHMsIGNvcnJlY3RlZApgYGB7ciwgZXZhbCA9IEZ9CihxdWFsaXR5QlBTX2RyaWZ0Y29ycmVjdGlvbiA8LSBwbG90X3NhbXBsZV9ib3hwbG90cyhjb3JyZWN0ZWQsIG9yZGVyX2J5ID0gIkNsYXNzIiwgdGl0bGUgPSAiYzE4ICgrKSBkcmlmdC1jb3JyZWN0ZWQgZmVhdHVyZSBhYnVuZGFuY2UiKSArCiAgIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoImxpZ2h0IGdyYXkiLCAiZGVlcHNreWJsdWUyIikpKQoKcGxvdF9zYW1wbGVfYm94cGxvdHMoY29ycmVjdGVkLCBvcmRlcl9ieSA9ICJJbmplY3Rpb25fb3JkZXIiLCB0aXRsZSA9ICJDb3JyZWN0ZWQgZmVhdHVyZSBhYnVuZGFuY2UiKQpgYGAKCgojIyBDb21wYXJlIHF1YWxpdHkgQlBzCmBgYHtyLCBmaWcuaGVpZ2h0PTgsIGV2YWw9Rn0KKHF1YWxpdHlCUHNfY29tcGFyZWQgPC0gZ2dhcnJhbmdlKHF1YWxpdHlCUHNfYjRjb3JyZWN0aW9uLCBxdWFsaXR5QlBTX2RyaWZ0Y29ycmVjdGlvbiwKICAgICAgICAgICAgICAgICAgICBuY29sID0gMiwgbnJvdyA9IDEpKQpgYGAKCgojIyBFeHBvcnQgbmV3IE1ldGFib3NldCB0byBFeGNlbCBzcHJlYWRzaGVldApgYGB7ciBldmFsID0gRkFMU0V9CndyaXRlX3RvX2V4Y2VsKGNvcnJlY3RlZCwgIm5vdGFtZV9kZnMvbWV0YWJvc2V0X2NvcnJlY3RlZC54bHN4IikKYGBgCgoKIyMgSW1wb3J0IGVkaXRlZCBNZXRhYm9zZXQKCmBgYHtyfQptZXRhYmRhdGFfY29ycmVjdGVkIDwtIHJlYWQuY3N2KGZpbGUgPSAibm90YW1lX2Rmcy9tZXRhYm9zZXRfY29ycmVjdGVkX2VkaXRlZGZvclIuY3N2IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjaGVjay5uYW1lcyA9IEZBTFNFKQpgYGAKCgojIyBXcmFuZ2xlIG5ldyBtZXRhYiBkYXRhCgojIyMgQ29tYmluZSBteiAmIHJ0IGJhY2sgdG9nZXRoZXIKCmBgYHtyfQptZXRhYmRhdGFfY29ycmVjdGVkX01aX1JUIDwtIG1ldGFiZGF0YV9jb3JyZWN0ZWQgJT4lCiAgbXV0YXRlKG1hc3MgPSByb3VuZChtZXRhYmRhdGFfY29ycmVjdGVkJG1hc3MsIGRpZ2l0cyA9IDQpLCAjIERlY3JlYXNlIG51bWJlciBvZiBkZWNpbWFscyBmb3IgbS96ICYgcnQKICAgICAgICAgcnQgPSByb3VuZChtZXRhYmRhdGFfY29ycmVjdGVkJHJ0LCBkaWdpdHMgPSAzKSwKICAgICAgICAgLmJlZm9yZT0xLAogICAgICAgICAua2VlcD0idW51c2VkIikgJT4lCiAgdW5pdGUobXpfcnQsIGMobWFzcywgcnQpLCByZW1vdmU9VFJVRSkgIyBDb21iaW5lIG0veiAmIHJ0IHdpdGggXyBpbiBiZXR3ZWVuCgpgYGAKCiMjIyBUcmFuc3Bvc2UgbmV3IGRmCgpgYGB7cn0KbWV0YWJkYXRhX2NvcnJlY3RlZF90IDwtIGFzLmRhdGEuZnJhbWUodChtZXRhYmRhdGFfY29ycmVjdGVkX01aX1JUKSkgJT4lCiAgcm93X3RvX25hbWVzKHJvd19udW1iZXIgPSAiZmluZF9oZWFkZXIiKSAlPiUgIyBtYWtlIE1aX1JUIGNvbHVtbiBuYW1lcwogIHJvd25hbWVzX3RvX2NvbHVtbih2YXIgPSAic3Vial9wZXJpb2QiKSAjIGNoYW5nZSByb3duYW1lcyB0byBjb2x1bW4gMQogIApgYGAKCiMjIyBCaW5kIG5ldyBkYXRhIHdpdGggbWV0YWRhdGEKCkkgd2FudCB0aGUgbmV3IGRyaWZ0IGNvcnJlY3RlZCAoREMpIGRmIHRvIGxvb2sganVzdCBsaWtlICJpbXBfbWV0YWJpbmRfY2x1c3RfbG9nMiIgZGYKCmBgYHtyfQojIGdvIGJhY2sgdG8gd2lkZSBkYXRhCmltcF9tZXRhYmluZF9jbHVzdF9sb2cyIDwtIGltcF9tZXRhYmluZF9jbHVzdF90aWR5X2xvZzIgJT4lCiAgZHBseXI6OnNlbGVjdCghcmVsX2FidW5kKSAlPiUKICBwaXZvdF93aWRlcihuYW1lc19mcm9tID0gbXpfcnQsCiAgICAgICAgICAgICAgdmFsdWVzX2Zyb20gPSByZWxfYWJ1bmRfbG9nMikKYGBgCgoKYGBge3J9CiMgY29tYmluZSBzdWJqZWN0IGFuZCBwZXJpb2QgY29sdW1ucyBmcm9tIGltcF9tZXRhYmluZF9jbHVzdF9sb2cyIGluIG9yZGVyIHRvIG1pbWljIERDIGRmCnN1YmpfcGVyX2ltcF9tZXRhYmluZF9jbHVzdF9sb2cyIDwtIGltcF9tZXRhYmluZF9jbHVzdF9sb2cyICU+JQogIHVuaXRlKHN1YmpfcGVyaW9kLCBjKFN1YmplY3QsIFBlcmlvZCksIHJlbW92ZSA9IEZBTFNFKQoKIyBwbGFjZSBuZXcgREMgb2JzZXJ2YXRpb25zIGluCkRDX2ltcF9tZXRhYmluZF9jbHVzdF9sb2cyIDwtIGZ1bGxfam9pbihzdWJqX3Blcl9pbXBfbWV0YWJpbmRfY2x1c3RfbG9nMlssYygxOjEyKV0sIG1ldGFiZGF0YV9jb3JyZWN0ZWRfdCwgYnkgPSAic3Vial9wZXJpb2QiKQoKIyB0YWtlIG91dCBvbGQgUUMgb2JzZXJ2YXRpb25zCkRDX2ltcF9tZXRhYmluZF9jbHVzdF9sb2cyIDwtIERDX2ltcF9tZXRhYmluZF9jbHVzdF9sb2cyICU+JQogIGZpbHRlcihzdWJqX3BlcmlvZCAhPSAiUUNfUUMiKQoKIyByZXBsYWNlIE5BcyBpbiBjb2x1bW5zIGZvciBRQ3MKRENfaW1wX21ldGFiaW5kX2NsdXN0X2xvZzJbaXMubmEoRENfaW1wX21ldGFiaW5kX2NsdXN0X2xvZzIpXSA8LSAiUUMiCmBgYAoKYGBge3J9CiN0aWR5IGRmCkRDX2ltcF9tZXRhYmluZF9jbHVzdF90aWR5X2xvZzIgPC0gRENfaW1wX21ldGFiaW5kX2NsdXN0X2xvZzIgJT4lCiAgcGl2b3RfbG9uZ2VyKDEzOm5jb2woLiksCiAgICAgICAgICAgICAgIG5hbWVzX3RvID0gIm16X3J0IiwKICAgICAgICAgICAgICAgdmFsdWVzX3RvID0gInJlbF9hYnVuZF9sb2cyIikgJT4lCiAgbXV0YXRlX2F0KCJyZWxfYWJ1bmRfbG9nMiIsIGFzLm51bWVyaWMpCmBgYAoKCiMgTG9hZCBGZWF0dXJlIElEIEtleQpIZXJlLCBJJ20gaW5zZXJ0aW5nIGEga2V5IHRoYXQgd291bGQgaW5kaWNhdGUgaWRlbnRpZmllZCBmZWF0dXJlcyBhdCBsZXZlbCAzIElEIG9yIGhpZ2hlci4KCmBgYHtyfQprZXlfb21pY3MgPC0gcmVhZF94bHN4KCIuLi9hbm5vdGF0ZWQtZmVhdHVyZXMtdGFibGUueGxzeCIsCiAgICAgICAgICAgICAgICAgc2hlZXQgPSAiRmVhdHVyZXMiKSAlPiUKICBjbGVhbl9uYW1lcygpICU+JQogIGZpbHRlcihsY19tb2RlX2MxOF9oaWxpYyA9PSAiQzE4IikgJT4lICMgTEMgbW9kZQogIGZpbHRlcihlc2lfbW9kZSA9PSAiKyIpICU+JSAjIEVTSSBtb2RlCiAgZHBseXI6OnNlbGVjdChtel9ydCwgYW5ub3RhdGlvbiwgbWV0YWJvbGl0ZV9jbGFzcywgcGFyZW50X2NvbXBvdW5kKSAjIHNlbGVjdCByZWxldmFudCBjb2x1bW5zCgojIGFkZCBrZXkgY29sdW1ucyAobGVmdF9qb2luIHRvIG9ubHkga2VlcCBhbGwgb2JzZXJ2YXRpb25zIHByZXNlbnQgaW4gZnVsbCBmZWF0dXJlIHRhYmxlKQphbm5vX2ltcF9tZXRhYmluZF9jbHVzdF90aWR5X2xvZzIgPC0gbGVmdF9qb2luKERDX2ltcF9tZXRhYmluZF9jbHVzdF90aWR5X2xvZzIsIGtleV9vbWljcywgYnkgPSAibXpfcnQiKSAlPiUKICAjIHJlcGxhY2UgTkFzIGluIGZlYXR1cmUgSUQgY29sdW1ucyB0byB1bi1hbm5vdGF0ZWQgZmVhdHVyZSBpZCdzIChtel9ydCkKICBtdXRhdGUoRmVhdHVyZV9JRCA9IGNvYWxlc2NlKGFubm90YXRpb24sIG16X3J0KSkKYGBgCgoKIyBQQ0FzCgojIyBXaXRoIFFDUwoKIyMjIFdyYW5nbGUKCmBgYHtyfQojIGdvIGJhY2sgdG8gd2lkZSBkYXRhCmFubm9faW1wX21ldGFiaW5kX2NsdXN0X2xvZzIgPC0gYW5ub19pbXBfbWV0YWJpbmRfY2x1c3RfdGlkeV9sb2cyICU+JQogIGRwbHlyOjpzZWxlY3QoYygxOjExKSwKICAgICAgICAgICAgICAgIEZlYXR1cmVfSUQsIHJlbF9hYnVuZF9sb2cyKSAlPiUKICBwaXZvdF93aWRlcihuYW1lc19mcm9tID0gRmVhdHVyZV9JRCwKICAgICAgICAgICAgICB2YWx1ZXNfZnJvbSA9IHJlbF9hYnVuZF9sb2cyKSAKYGBgCgpgYGB7cn0KUENBLkRDX2ltcF9tZXRhYmluZF9jbHVzdF9sb2cyIDwtIFBDQShhbm5vX2ltcF9tZXRhYmluZF9jbHVzdF9sb2cyLCAgIyB3aWRlIGRhdGEKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBxdWFsaS5zdXAgPSAxOjExLCAjIHJlbW92ZSBxdWFsaXRhdGl2ZSB2YXJpYWJsZXMKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBncmFwaCA9IEZBTFNFLCAjIGRvbid0IGdyYXBoCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2NhbGUudW5pdCA9IEZBTFNFKSAjIGRvbid0IHNjYWxlLCBhbHJlYWR5IHRyYW5zZm9ybWVkIGRhdGEKCiMgUENBIHN1bW1hcnkKa2FibGUoc3VtbWFyeShQQ0EuRENfaW1wX21ldGFiaW5kX2NsdXN0X2xvZzIpKQpgYGAKCmBgYHtyfQojIHB1bGwgUEMgY29vcmRpbmF0ZXMgaW50byBkZgpQQ19jb29yZF9RQ19sb2cyIDwtIGFzLmRhdGEuZnJhbWUoUENBLkRDX2ltcF9tZXRhYmluZF9jbHVzdF9sb2cyJGluZCRjb29yZCkKCiMgYmluZCBiYWNrIG1ldGFkYXRhIGZyb20gY29scyAxLTEwClBDX2Nvb3JkX1FDX2xvZzIgPC0gYmluZF9jb2xzKGFubm9faW1wX21ldGFiaW5kX2NsdXN0X2xvZzJbLDE6MTFdLCBQQ19jb29yZF9RQ19sb2cyKQoKIyBncmFiIHNvbWUgdmFyaWFuY2UgZXhwbGFpbmVkCmltcG9ydGFuY2VfUUMgPC0gUENBLkRDX2ltcF9tZXRhYmluZF9jbHVzdF9sb2cyJGVpZwoKIyBzZXQgdmFyaWFuY2UgZXhwbGFpbmVkIHdpdGggUEMxLCByb3VuZCB0byAyIGRpZ2l0cwpQQzFfd2l0aFFDIDwtIHJvdW5kKGltcG9ydGFuY2VfUUNbMSwyXSwgMikKCiMgc2V0IHZhcmlhbmNlIGV4cGxhaW5lZCB3aXRoIFBDMiwgcm91bmQgdG8gMiBkaWdpdHMKUEMyX3dpdGhRQyA8LSByb3VuZChpbXBvcnRhbmNlX1FDWzIsMl0sIDIpCmBgYAoKIyMjIFBsb3RzClVzaW5nIEZhY3RvRXh0cmEgcGFja2FnZQpgYGB7cn0KIyBzY3JlZSBwbG90CmZ2aXpfZWlnKFBDQS5EQ19pbXBfbWV0YWJpbmRfY2x1c3RfbG9nMikKCiMgZ2V0IGVpZ2VudmFsdWVzCmthYmxlKGdldF9laWcoUENBLkRDX2ltcF9tZXRhYmluZF9jbHVzdF9sb2cyKSkKYGBgCgpgYGB7cn0KIyBzY29yZXMgcGxvdApmdml6X3BjYV9pbmQoUENBLkRDX2ltcF9tZXRhYmluZF9jbHVzdF9sb2cyKQpgYGAKCiMjIyBNYW51YWwgc2NvcmVzIHBsb3RzCmBgYHtyfQojIG1hbnVhbCBzY29yZXMgcGxvdAooUENBX3dpdGhRQ3MgPC0gUENfY29vcmRfUUNfbG9nMiAlPiUKICBnZ3Bsb3QoYWVzKHggPSBEaW0uMSwgeSA9IERpbS4yLAogICAgICAgICAgICAgZmlsbCA9IGZhY3RvcihJbnRlcnZlbnRpb24sIGxldmVscyA9IGMoIlllbGxvdyIsICJSZWQiLCAiUUMiKSkpKSArCiAgZ2VvbV9wb2ludChzaGFwZSA9IDIxLCBhbHBoYSA9IDAuOCkgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoImdvbGQiLCAidG9tYXRvMSIsICJsaWdodCBncmV5IikpICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gImJsYWNrIikgKyAgCiAgdGhlbWVfbWluaW1hbCgpICsKICBjb29yZF9maXhlZChQQzJfd2l0aFFDL1BDMV93aXRoUUMpICsKICBsYWJzKHggPSBnbHVlOjpnbHVlKCJQQzE6IHtQQzFfd2l0aFFDfSUiKSwKICAgICAgIHkgPSBnbHVlOjpnbHVlKCJQQzI6IHtQQzJfd2l0aFFDfSUiKSwKICAgICAgIGZpbGwgPSAiR3JvdXAiLAogICAgICAgdGl0bGUgPSAiUHJpbmNpcGFsIENvbXBvbmVudHMgQW5hbHlzaXMgU2NvcmVzIFBsb3QiLAogICAgICAgc3VidGl0bGUgPSAiTG9nMiB0cmFuc2Zvcm1lZCBkYXRhIikpCmBgYAoKIyMgV2l0aG91dCBRQ3MKCiMjIyBXcmFuZ2xlIAoKYGBge3J9CmFubm9faW1wX21ldGFiaW5kX2NsdXN0X2xvZzJfbm9RQ3MgPC0gYW5ub19pbXBfbWV0YWJpbmRfY2x1c3RfbG9nMiAlPiUKICBmaWx0ZXIoSW50ZXJ2ZW50aW9uICE9ICJRQyIpCgpQQ0EuRENfaW1wX21ldGFiaW5kX2NsdXN0X2xvZzJfbm9RQ3MgPC0gUENBKGFubm9faW1wX21ldGFiaW5kX2NsdXN0X2xvZzJfbm9RQ3MsICMgd2lkZSBkYXRhCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBxdWFsaS5zdXA9MToxMSwgIyByZW1vdmUgcXVhbGl0YXRpdmUgdmFyaWFibGVzCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBncmFwaD1GQUxTRSwgIyBkb24ndCBncmFwaAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2NhbGUudW5pdD1GQUxTRSkgIyBkb24ndCBzY2FsZSwgd2UgYWxyZWFkeSBkaWQgdGhpcwoKIyBsb29rIGF0IHN1bW1hcnkKa2FibGUoc3VtbWFyeShQQ0EuRENfaW1wX21ldGFiaW5kX2NsdXN0X2xvZzJfbm9RQ3MpKQpgYGAKCmBgYHtyfQojIHB1bGwgUEMgY29vcmRpbmF0ZXMgaW50byBkZgpQQ19jb29yZF9ub1FDc19sb2cyIDwtIGFzLmRhdGEuZnJhbWUoUENBLkRDX2ltcF9tZXRhYmluZF9jbHVzdF9sb2cyX25vUUNzJGluZCRjb29yZCkKCiMgYmluZCBiYWNrIG1ldGFkYXRhIGZyb20gY29scyAxLTEwClBDX2Nvb3JkX25vUUNzX2xvZzIgPC0gYmluZF9jb2xzKGFubm9faW1wX21ldGFiaW5kX2NsdXN0X2xvZzJfbm9RQ3NbLDE6MTFdLCBQQ19jb29yZF9ub1FDc19sb2cyKQoKIyBncmFiIHNvbWUgdmFyaWFuY2UgZXhwbGFpbmVkCmltcG9ydGFuY2Vfbm9RQyA8LSBQQ0EuRENfaW1wX21ldGFiaW5kX2NsdXN0X2xvZzJfbm9RQ3MkZWlnCgojIHNldCB2YXJpYW5jZSBleHBsYWluZWQgd2l0aCBQQzEsIHJvdW5kIHRvIDIgZGlnaXRzClBDMV9ub1FDIDwtIHJvdW5kKGltcG9ydGFuY2Vfbm9RQ1sxLDJdLCAyKQoKIyBzZXQgdmFyaWFuY2UgZXhwbGFpbmVkIHdpdGggUEMyLCByb3VuZCB0byAyIGRpZ2l0cwpQQzJfbm9RQyA8LSByb3VuZChpbXBvcnRhbmNlX25vUUNbMiwyXSwgMikKYGBgCgojIyMgUGxvdHMKVXNpbmcgRmFjdG9FeHRyYQoKYGBge3J9CiMgc2NyZWUgcGxvdApmdml6X2VpZyhQQ0EuRENfaW1wX21ldGFiaW5kX2NsdXN0X2xvZzJfbm9RQ3MpCmBgYAoKYGBge3J9CiMgc2NvcmVzIHBsb3QKZnZpel9wY2FfaW5kKFBDQS5EQ19pbXBfbWV0YWJpbmRfY2x1c3RfbG9nMl9ub1FDcykKYGBgCgoKYGBge3J9CiMgcGxvdCBvZiBjb250cmlidXRpb25zIGZyb20gZmVhdHVyZXMgdG8gUEMxCih2YXJfY29udHJpYl9ub1FDc19QQzEgPC0gZnZpel9jb250cmliKFBDQS5EQ19pbXBfbWV0YWJpbmRfY2x1c3RfbG9nMl9ub1FDcywKICAgICAgICAgICAgIGNob2ljZSA9ICJ2YXIiLAogICAgICAgICAgICAgYXhlcyA9IDEsCiAgICAgICAgICAgICB0b3AgPSAyNSwKICAgICAgICAgICAgIHRpdGxlID0gIlZhciBjb250cmlidXRpb24gdG8gUEMxOiBubyBRQ3MiKSkKCiMgcGxvdCBvZiBjb250cmlidXRpb25zIGZyb20gZmVhdHVyZXMgdG8gUEMyCih2YXJfY29udHJpYl9ub1FDc19QQzIgPC0gZnZpel9jb250cmliKFBDQS5EQ19pbXBfbWV0YWJpbmRfY2x1c3RfbG9nMl9ub1FDcywKICAgICAgICAgICAgIGNob2ljZSA9ICJ2YXIiLAogICAgICAgICAgICAgYXhlcyA9IDIsCiAgICAgICAgICAgICB0b3AgPSAyNSwKICAgICAgICAgICAgIHRpdGxlID0gIlZhciBjb250cmlidXRpb24gdG8gUEMyOiBubyBRQ3MiKSkKYGBgCgojIyMgTWFudWFsIHNjb3JlcyBwbG90cwoKIyMjIyBZZWxsb3cgdnMgcmVkCmBgYHtyfQooUENBX3dpdGhvdXRRQ3MgPC0gUENfY29vcmRfbm9RQ3NfbG9nMiAlPiUKICBnZ3Bsb3QoYWVzKHggPSBEaW0uMSwgCiAgICAgICAgICAgICB5ID0gRGltLjIsCiAgICAgICAgICAgICBmaWxsID0gSW50ZXJ2ZW50aW9uKSkgKwogICAgZ2VvbV9wb2ludChzaGFwZSA9IDIxLCBhbHBoYSA9IDAuOCkgKwogICAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCwgbGluZXR5cGUgPSAiZGFzaGVkIiwgYWxwaGE9MC41KSArCiAgICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAwLCBsaW5ldHlwZSA9ICJkYXNoZWQiLCBhbHBoYT0wLjUpICsKICAgIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoImdvbGQiLCAidG9tYXRvMSIpKSArCiAgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gImJsYWNrIikgKyAgCiAgICB0aGVtZV9taW5pbWFsKCkgKwogICAgY29vcmRfZml4ZWQoUEMyX25vUUMvUEMxX25vUUMpICsKICAgIGxhYnMoeCA9IGdsdWU6OmdsdWUoIlBDMToge1BDMV9ub1FDfSUiKSwKICAgICAgICAgeSA9IGdsdWU6OmdsdWUoIlBDMjoge1BDMl9ub1FDfSUiKSwKICAgICAgICAgZmlsbCA9ICJJbnRlcnZlbnRpb24iLAogICAgICAgICB0aXRsZSA9ICJQcmluY2lwYWwgQ29tcG9uZW50cyBBbmFseXNpcyBTY29yZXMgUGxvdCIsCiAgICAgICAgIHN1YnRpdGxlID0gIkxvZzIgdHJhbnNmb3JtZWQgZGF0YSwgd2l0aG91dCBRQ3MiKSkKZ2dwbG90bHkoUENBX3dpdGhvdXRRQ3MpCmBgYAoKIyMjIyBwcmUgdnMgcG9zdApgYGB7cn0KKFBDQV93aXRob3V0UUNzLnByZV9wb3N0IDwtIFBDX2Nvb3JkX25vUUNzX2xvZzIgJT4lCiAgZ2dwbG90KGFlcyh4ID0gRGltLjEsIAogICAgICAgICAgICAgeSA9IERpbS4yLAogICAgICAgICAgICAgZmlsbCA9IGZhY3RvcihwcmVfcG9zdF9pbnRlcnZlbnRpb24sIGxldmVscyA9IGMoInByZV9ZZWxsb3ciLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInBvc3RfWWVsbG93IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJwcmVfUmVkIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJwb3N0X1JlZCIpKSwKICAgICAgICAgICAgIHRleHQgPSBzYW1wbGVfSUQpKSArCiAgICBnZW9tX3BvaW50KHNoYXBlID0gMjEsIGFscGhhID0gMC44KSArCiAgICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwLCBsaW5ldHlwZSA9ICJkYXNoZWQiLCBhbHBoYT0wLjUpICsKICAgIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IDAsIGxpbmV0eXBlID0gImRhc2hlZCIsIGFscGhhPTAuNSkgKwogICAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygiZ3JheSIsICJ5ZWxsb3cxIiwgInBpbmsxIiwgInJlZDIiKSkgKwogICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9ICJibGFjayIpICsgIAogICAgdGhlbWVfbWluaW1hbCgpICsKICAgIGNvb3JkX2ZpeGVkKFBDMl9ub1FDL1BDMV9ub1FDKSArCiAgICBsYWJzKHggPSBnbHVlOjpnbHVlKCJQQzE6IHtQQzFfbm9RQ30lIiksCiAgICAgICAgIHkgPSBnbHVlOjpnbHVlKCJQQzI6IHtQQzJfbm9RQ30lIiksCiAgICAgICAgIGZpbGwgPSAicHJlX3Bvc3QiLAogICAgICAgICB0aXRsZSA9ICJQcmluY2lwYWwgQ29tcG9uZW50cyBBbmFseXNpcyBTY29yZXMgUGxvdCIsCiAgICAgICAgIHN1YnRpdGxlID0gIkxvZzIgdHJhbnNmb3JtZWQsIHdpdGhvdXQgUUNzIikpCmdncGxvdGx5KFBDQV93aXRob3V0UUNzLnByZV9wb3N0LAogICAgICAgICB0b29sdGlwID0gInRleHQiKSAKYGBgCgpGcm9tIGxvb2tpbmcgYXQgdGhlIFBDQSBwbG90cywgc3ViamVjdCA2MTA2IGFuZCA2MTEyIGFyZSB2aXN1YWwgb3V0bGllcnMuIExldCdzIHJlbW92ZSB0aGVtLgoKCiMjIFJlbW92YWwgb2Ygb3V0bGllcgoKIyMjIFdpdGggUUNzCgojIyMjIFdyYW5nbGUKCgpgYGB7cn0KIyBnbyBiYWNrIHRvIHdpZGUgZGF0YQpEQ19pbXBfbm9vdXRsaWVyc19sb2cyIDwtIGFubm9faW1wX21ldGFiaW5kX2NsdXN0X2xvZzIgJT4lCiAgZmlsdGVyKFN1YmplY3QgIT0gNjEwNiwKICAgICAgICAgU3ViamVjdCAhPSA2MTEyKQoKUENBLkRDX2ltcF9ub291dGxpZXJzX2xvZzIgPC0gUENBKERDX2ltcF9ub291dGxpZXJzX2xvZzIsICAjIHdpZGUgZGF0YQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHF1YWxpLnN1cCA9IDE6MTEsICMgcmVtb3ZlIHF1YWxpdGF0aXZlIHZhcmlhYmxlcwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdyYXBoID0gRkFMU0UsICMgZG9uJ3QgZ3JhcGgKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzY2FsZS51bml0ID0gRkFMU0UpICMgZG9uJ3Qgc2NhbGUsIGFscmVhZHkgdHJhbnNmb3JtZWQgZGF0YQoKIyBQQ0Egc3VtbWFyeQpzdW1tYXJ5KFBDQS5EQ19pbXBfbm9vdXRsaWVyc19sb2cyKQpgYGAKCmBgYHtyfQojIHB1bGwgUEMgY29vcmRpbmF0ZXMgaW50byBkZgpQQ19ub291dGxpZXJzX1FDX2xvZzIgPC0gYXMuZGF0YS5mcmFtZShQQ0EuRENfaW1wX25vb3V0bGllcnNfbG9nMiRpbmQkY29vcmQpCgojIGJpbmQgYmFjayBtZXRhZGF0YSBmcm9tIGNvbHMgMS0xMQpQQ19ub291dGxpZXJzX1FDX2xvZzIgPC0gYmluZF9jb2xzKERDX2ltcF9ub291dGxpZXJzX2xvZzJbLDE6MTFdLCBQQ19ub291dGxpZXJzX1FDX2xvZzIpCgojIGdyYWIgc29tZSB2YXJpYW5jZSBleHBsYWluZWQKaW1wb3J0YW5jZV9ub291dGxpZXJzX1FDIDwtIFBDQS5EQ19pbXBfbm9vdXRsaWVyc19sb2cyJGVpZwoKIyBzZXQgdmFyaWFuY2UgZXhwbGFpbmVkIHdpdGggUEMxLCByb3VuZCB0byAyIGRpZ2l0cwpQQzFfbm9vdXRsaWVyc193aXRoUUMgPC0gcm91bmQoaW1wb3J0YW5jZV9ub291dGxpZXJzX1FDWzEsMl0sIDIpCgojIHNldCB2YXJpYW5jZSBleHBsYWluZWQgd2l0aCBQQzIsIHJvdW5kIHRvIDIgZGlnaXRzClBDMl9ub291dGxpZXJzX3dpdGhRQyA8LSByb3VuZChpbXBvcnRhbmNlX25vb3V0bGllcnNfUUNbMiwyXSwgMikKYGBgCgojIyMjIFBsb3RzClVzaW5nIEZhY3RvRXh0cmEgcGFja2FnZQpgYGB7cn0KIyBzY3JlZSBwbG90CmZ2aXpfZWlnKFBDQS5EQ19pbXBfbm9vdXRsaWVyc19sb2cyKQpgYGAKCmBgYHtyfQojIHNjb3JlcyBwbG90CmZ2aXpfcGNhX2luZChQQ0EuRENfaW1wX25vb3V0bGllcnNfbG9nMikKYGBgCgoKIyMjIyBNYW51YWwgc2NvcmVzIHBsb3RzCgogIyMjIyMgUmVkIHZzIHllbGxvdwpgYGB7cn0KIyBtYW51YWwgc2NvcmVzIHBsb3QKKFBDQV9ub291dGxpZXJzX3dpdGhRQ3MgPC0gUENfbm9vdXRsaWVyc19RQ19sb2cyICU+JQogIGdncGxvdChhZXMoeCA9IERpbS4xLCB5ID0gRGltLjIsCiAgICAgICAgICAgICBmaWxsID0gZmFjdG9yKEludGVydmVudGlvbiwgbGV2ZWxzID0gYygiWWVsbG93IiwgIlJlZCIsICJRQyIpKSkpICsKICBnZW9tX3BvaW50KHNoYXBlID0gMjEsIGFscGhhID0gMC44KSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygiZ29sZCIsICJ0b21hdG8xIiwgImxpZ2h0IGdyZXkiKSkgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSAiYmxhY2siKSArICAKICB0aGVtZV9taW5pbWFsKCkgKwogIGxhYnMoeCA9IGdsdWU6OmdsdWUoIlBDMToge1BDMV9ub291dGxpZXJzX3dpdGhRQ30lIiksCiAgICAgICB5ID0gZ2x1ZTo6Z2x1ZSgiUEMyOiB7UEMyX25vb3V0bGllcnNfd2l0aFFDfSUiKSwKICAgICAgIGZpbGwgPSAiR3JvdXAiLAogICAgICAgdGl0bGUgPSAiUHJpbmNpcGFsIENvbXBvbmVudHMgQW5hbHlzaXMgU2NvcmVzIFBsb3QiKSkKYGBgCgojIyMjIyBQcmUgdnMgcG9zdApgYGB7cn0KKFBDQV9ub291dGxpZXJzX3ByZXBvc3Rfd2l0aFFDcyA8LSBQQ19ub291dGxpZXJzX1FDX2xvZzIgJT4lCiAgZ2dwbG90KGFlcyh4ID0gRGltLjEsIAogICAgICAgICAgICAgeSA9IERpbS4yLAogICAgICAgICAgICAgZmlsbCA9IGZhY3RvcihwcmVfcG9zdF9pbnRlcnZlbnRpb24sIGxldmVscyA9IGMoInByZV9ZZWxsb3ciLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInBvc3RfWWVsbG93IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJwcmVfUmVkIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJwb3N0X1JlZCIpKSwKICAgICAgICAgICAgIHRleHQgPSBzYW1wbGVfSUQpKSArCiAgICBnZW9tX3BvaW50KHNoYXBlID0gMjEsIGFscGhhID0gMC44KSArCiAgICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwLCBsaW5ldHlwZSA9ICJkYXNoZWQiLCBhbHBoYT0wLjUpICsKICAgIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IDAsIGxpbmV0eXBlID0gImRhc2hlZCIsIGFscGhhPTAuNSkgKwogICAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygiZ3JheSIsICJ5ZWxsb3cxIiwgInBpbmsxIiwgInJlZDIiKSkgKwogICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9ICJibGFjayIpICsgIAogICAgdGhlbWVfbWluaW1hbCgpICsKICAgIGxhYnMoeCA9IGdsdWU6OmdsdWUoIlBDMToge1BDMV9ub291dGxpZXJzX3dpdGhRQ30lIiksCiAgICAgICAgIHkgPSBnbHVlOjpnbHVlKCJQQzI6IHtQQzJfbm9vdXRsaWVyc193aXRoUUN9JSIpLAogICAgICAgICBmaWxsID0gInByZV9wb3N0IiwKICAgICAgICAgdGl0bGUgPSAiUHJpbmNpcGFsIENvbXBvbmVudHMgQW5hbHlzaXMgU2NvcmVzIFBsb3QiKSkKZ2dwbG90bHkoUENBX25vb3V0bGllcnNfcHJlcG9zdF93aXRoUUNzLAogICAgICAgICB0b29sdGlwID0gInRleHQiKSAKYGBgCgoKIyMjIFdpdGhvdXQgUUNzCgojIyMjIFdyYW5nbGUKYGBge3J9CmltcF9ub291dGxpZXJzX25vUUNzX2xvZzIgPC0gRENfaW1wX25vb3V0bGllcnNfbG9nMiAlPiUKICBmaWx0ZXIoSW50ZXJ2ZW50aW9uICE9ICJRQyIpIAoKUENBLmltcF9ub291dGxpZXJzX25vUUNzX2xvZzIgPC0gUENBKGltcF9ub291dGxpZXJzX25vUUNzX2xvZzIsICMgd2lkZSBkYXRhCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBxdWFsaS5zdXA9MToxMSwgIyByZW1vdmUgcXVhbGl0YXRpdmUgdmFyaWFibGVzCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBncmFwaD1GQUxTRSwgIyBkb24ndCBncmFwaAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2NhbGUudW5pdD1GQUxTRSkgIyBkb24ndCBzY2FsZSwgd2UgYWxyZWFkeSBkaWQgdGhpcwoKIyBsb29rIGF0IHN1bW1hcnkKa2FibGUoc3VtbWFyeShQQ0EuaW1wX25vb3V0bGllcnNfbm9RQ3NfbG9nMikpCmBgYAoKYGBge3J9CiMgcHVsbCBQQyBjb29yZGluYXRlcyBpbnRvIGRmClBDX2Nvb3JkX25vb3V0bGllcnNfbm9RQ19sb2cyIDwtIGFzLmRhdGEuZnJhbWUoUENBLmltcF9ub291dGxpZXJzX25vUUNzX2xvZzIkaW5kJGNvb3JkKQoKIyBiaW5kIGJhY2sgbWV0YWRhdGEgZnJvbSBjb2xzIDEtMTEKUENfY29vcmRfbm9vdXRsaWVyc19ub1FDX2xvZzIgPC0gYmluZF9jb2xzKGltcF9ub291dGxpZXJzX25vUUNzX2xvZzJbLDE6MTFdLCBQQ19jb29yZF9ub291dGxpZXJzX25vUUNfbG9nMikKCiMgZ3JhYiBzb21lIHZhcmlhbmNlIGV4cGxhaW5lZAppbXBvcnRhbmNlX25vb3V0bGllcnNfbm9RQyA8LSBQQ0EuaW1wX25vb3V0bGllcnNfbm9RQ3NfbG9nMiRlaWcKCiMgc2V0IHZhcmlhbmNlIGV4cGxhaW5lZCB3aXRoIFBDMSwgcm91bmQgdG8gMiBkaWdpdHMKUEMxX25vb3V0bGllcnNfbm9RQyA8LSByb3VuZChpbXBvcnRhbmNlX25vb3V0bGllcnNfbm9RQ1sxLDJdLCAyKQoKIyBzZXQgdmFyaWFuY2UgZXhwbGFpbmVkIHdpdGggUEMyLCByb3VuZCB0byAyIGRpZ2l0cwpQQzJfbm9vdXRsaWVyc19ub1FDIDwtIHJvdW5kKGltcG9ydGFuY2Vfbm9vdXRsaWVyc19ub1FDWzIsMl0sIDIpCmBgYAoKCiMjIyMgUGxvdHMKVXNpbmcgRmFjdG9FeHRyYQpgYGB7cn0KIyBzY3JlZSBwbG90CmZ2aXpfZWlnKFBDQS5pbXBfbm9vdXRsaWVyc19ub1FDc19sb2cyKQpgYGAKCmBgYHtyfQojIHNjb3JlcyBwbG90CmZ2aXpfcGNhX2luZChQQ0EuaW1wX25vb3V0bGllcnNfbm9RQ3NfbG9nMikKYGBgCgoKYGBge3J9CiMgcGxvdCBvZiBjb250cmlidXRpb25zIGZyb20gZmVhdHVyZXMgdG8gUEMxCih2YXJfY29udHJpYl9ub291dGxpZXJzX25vUUNzX1BDMSA8LSBmdml6X2NvbnRyaWIoUENBLmltcF9ub291dGxpZXJzX25vUUNzX2xvZzIsCiAgICAgICAgICAgICBjaG9pY2UgPSAidmFyIiwKICAgICAgICAgICAgIGF4ZXMgPSAxLAogICAgICAgICAgICAgdG9wID0gMjAsCiAgICAgICAgICAgICB0aXRsZSA9ICJWYXIgY29udHJpYnV0aW9uIHRvIFBDMTogbm8gb3V0bGllcnMsIG5vIFFDcyIpKQoKIyBwbG90IG9mIGNvbnRyaWJ1dGlvbnMgZnJvbSBmZWF0dXJlcyB0byBQQzIKKHZhcl9jb250cmliX25vb3V0bGllcnNfbm9RQ3NfUEMyIDwtIGZ2aXpfY29udHJpYihQQ0EuaW1wX25vb3V0bGllcnNfbm9RQ3NfbG9nMiwKICAgICAgICAgICAgIGNob2ljZSA9ICJ2YXIiLAogICAgICAgICAgICAgYXhlcyA9IDIsCiAgICAgICAgICAgICB0b3AgPSAyMCwKICAgICAgICAgICAgIHRpdGxlID0gIlZhciBjb250cmlidXRpb24gdG8gUEMyOiBubyBvdXRsaWVycywgbm8gUUNzIikpCmBgYAoKCiMjIyMgTWFudWFsIHNjb3JlcyBwbG90cwoKIyMjIyMgUmVkIHZzIHllbGxvdwpgYGB7cn0KKFBDQV9ub291dGxpZXJzX3dpdGhvdXRRQ3MgPC0gUENfY29vcmRfbm9vdXRsaWVyc19ub1FDX2xvZzIgJT4lCiAgZ2dwbG90KGFlcyh4ID0gRGltLjEsIAogICAgICAgICAgICAgeSA9IERpbS4yLAogICAgICAgICAgICAgZmlsbCA9IEludGVydmVudGlvbikpICsKICAgIGdlb21fcG9pbnQoc2hhcGUgPSAyMSwgYWxwaGEgPSAwLjgpICsKICAgIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDAsIGxpbmV0eXBlID0gImRhc2hlZCIsIGFscGhhPTAuNSkgKwogICAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gMCwgbGluZXR5cGUgPSAiZGFzaGVkIiwgYWxwaGE9MC41KSArCiAgICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCJ0b21hdG8xIiwgImdvbGQiKSkgKwogICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9ICJibGFjayIpICsgIAogICAgdGhlbWVfbWluaW1hbCgpICsKICAgIGNvb3JkX2ZpeGVkKFBDMl9ub291dGxpZXJzX25vUUMvUEMxX25vb3V0bGllcnNfbm9RQykgKwogICAgbGFicyh4ID0gZ2x1ZTo6Z2x1ZSgiUEMxOiB7UEMxX25vb3V0bGllcnNfbm9RQ30lIiksCiAgICAgICAgIHkgPSBnbHVlOjpnbHVlKCJQQzI6IHtQQzJfbm9vdXRsaWVyc19ub1FDfSUiKSwKICAgICAgICAgZmlsbCA9ICJJbnRlcnZlbnRpb24iLAogICAgICAgICB0aXRsZSA9ICJQcmluY2lwYWwgQ29tcG9uZW50cyBBbmFseXNpcyBTY29yZXMgUGxvdCIpKQpnZ3Bsb3RseShQQ0Ffbm9vdXRsaWVyc193aXRob3V0UUNzKQpgYGAKCgojIyMjIyBQcmUgdnMgcG9zdApgYGB7cn0KKFBDQV9ub291dGxpZXJzX25vUUNzLnByZXBvc3QgPC0gUENfY29vcmRfbm9vdXRsaWVyc19ub1FDX2xvZzIgJT4lCiAgZ2dwbG90KGFlcyh4ID0gRGltLjEsIAogICAgICAgICAgICAgeSA9IERpbS4yLAogICAgICAgICAgICAgZmlsbCA9IGZhY3RvcihwcmVfcG9zdF9pbnRlcnZlbnRpb24sIGxldmVscyA9IGMoInByZV9ZZWxsb3ciLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInBvc3RfWWVsbG93IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJwcmVfUmVkIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJwb3N0X1JlZCIpKSwKICAgICAgICAgICAgIHRleHQgPSBzYW1wbGVfSUQpKSArCiAgICBnZW9tX3BvaW50KHNoYXBlID0gMjEsIGFscGhhID0gMC44KSArCiAgICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwLCBsaW5ldHlwZSA9ICJkYXNoZWQiLCBhbHBoYT0wLjUpICsKICAgIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IDAsIGxpbmV0eXBlID0gImRhc2hlZCIsIGFscGhhPTAuNSkgKwogICAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygiZ3JheSIsICJ5ZWxsb3cxIiwgInBpbmsxIiwgInJlZDIiKSkgKwogICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9ICJibGFjayIpICsgIAogICAgdGhlbWVfbWluaW1hbCgpICsKICAgIGNvb3JkX2ZpeGVkKFBDMl9ub291dGxpZXJzX25vUUMvUEMxX25vb3V0bGllcnNfbm9RQykgKwogICAgbGFicyh4ID0gZ2x1ZTo6Z2x1ZSgiUEMxOiB7UEMxX25vb3V0bGllcnNfbm9RQ30lIiksCiAgICAgICAgIHkgPSBnbHVlOjpnbHVlKCJQQzI6IHtQQzJfbm9vdXRsaWVyc19ub1FDfSUiKSwKICAgICAgICAgZmlsbCA9ICJwcmVfcG9zdCIsCiAgICAgICAgIHRpdGxlID0gIlByaW5jaXBhbCBDb21wb25lbnRzIEFuYWx5c2lzIFNjb3JlcyBQbG90IiwKICAgICAgICAgc3VidGl0bGUgPSAiTG9nMiB0cmFuc2Zvcm1lZCBkYXRhLCBubyBvdXRsaWVycyIpKQpnZ3Bsb3RseShQQ0Ffbm9vdXRsaWVyc19ub1FDcy5wcmVwb3N0LAogICAgICAgICB0b29sdGlwID0gInRleHQiKSAKYGBgCgoKIyMjIyMgTSB2IEYKYGBge3J9CihQQ0Ffbm9vdXRsaWVyc19ub1FDcy5NdnNGIDwtIFBDX2Nvb3JkX25vb3V0bGllcnNfbm9RQ19sb2cyICU+JQogIGdncGxvdChhZXMoeCA9IERpbS4xLCAKICAgICAgICAgICAgIHkgPSBEaW0uMiwKICAgICAgICAgICAgIGZpbGwgPSBmYWN0b3IoU2V4LCBsZXZlbHMgPSBjKCJNIiwiRiIpKSwKICAgICAgICAgICAgIHRleHQgPSBzYW1wbGVfSUQpKSArCiAgICBnZW9tX3BvaW50KHNoYXBlID0gMjEsIGFscGhhID0gMC44KSArCiAgICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwLCBsaW5ldHlwZSA9ICJkYXNoZWQiLCBhbHBoYT0wLjUpICsKICAgIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IDAsIGxpbmV0eXBlID0gImRhc2hlZCIsIGFscGhhPTAuNSkgKwogICAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygiZ3JlZW4iLCAicGluayIpKSArCiAgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gImJsYWNrIikgKyAgCiAgICB0aGVtZV9taW5pbWFsKCkgKwogICAgY29vcmRfZml4ZWQoUEMyX25vb3V0bGllcnNfbm9RQy9QQzFfbm9vdXRsaWVyc19ub1FDKSArCiAgICBsYWJzKHggPSBnbHVlOjpnbHVlKCJQQzE6IHtQQzFfbm9vdXRsaWVyc19ub1FDfSUiKSwKICAgICAgICAgeSA9IGdsdWU6OmdsdWUoIlBDMjoge1BDMl9ub291dGxpZXJzX25vUUN9JSIpLAogICAgICAgICBmaWxsID0gInByZV9wb3N0IiwKICAgICAgICAgdGl0bGUgPSAiUHJpbmNpcGFsIENvbXBvbmVudHMgQW5hbHlzaXMgU2NvcmVzIFBsb3QiLAogICAgICAgICBzdWJ0aXRsZSA9ICJMb2cyIHRyYW5zZm9ybWVkIGRhdGEsIG5vIDYxMDYiKSkKZ2dwbG90bHkoUENBX25vb3V0bGllcnNfbm9RQ3MuTXZzRiwKICAgICAgICAgdG9vbHRpcCA9ICJ0ZXh0IikKYGBgCgoKCiMgUENBdG9vbHMgcGNrZwoKIyMgVy8gT3V0bGllcnMKCiMjIyBEYXRhIHdyYW5nbGluZwpgYGB7cn0KIyBjcmVhdGUgcmVsIGFidW5kIGRmIHN1aXRhYmxlIGZvciBQQ0F0b29scyBwYWNrYWdlCmltcF9jbHVzdF9vbWljc2RhdGFfb3V0bGllcnNfZm9yUENBdG9vbHMgPC0gYXMuZGF0YS5mcmFtZSh0KGFubm9faW1wX21ldGFiaW5kX2NsdXN0X2xvZzJbLC1jKDI6MTEpXSkpICMgdHJhbnNwb3NlIGRmICh1c2luZyBkZiB3aXRoIGtleSkKCm5hbWVzKGltcF9jbHVzdF9vbWljc2RhdGFfb3V0bGllcnNfZm9yUENBdG9vbHMpIDwtIGltcF9jbHVzdF9vbWljc2RhdGFfb3V0bGllcnNfZm9yUENBdG9vbHNbMSxdICMgbWFrZSBzYW1wbGUgSURzIGNvbHVtbiBuYW1lcwoKaW1wX2NsdXN0X29taWNzZGF0YV9vdXRsaWVyc19mb3JQQ0F0b29scyA8LSBpbXBfY2x1c3Rfb21pY3NkYXRhX291dGxpZXJzX2ZvclBDQXRvb2xzWy0xLF0gIyByZW1vdmUgc2FtcGxlIElEIHJvdwoKIyBjcmVhdGUgbWV0YWRhdGEgZGYgc3VpdGFibGUgZm9yIFBDQXRvb2xzIHBja2cKbWV0YWRhdGFfb3V0bGllcnNfZm9yUENBdG9vbHMgPC0gbWV0YWRhdGEgJT4lCiAgY29sdW1uX3RvX3Jvd25hbWVzKHZhciA9ICJzYW1wbGVfSUQiKSAjIGNoYW5nZSBzYW1wbGUgSUQgY29sdW1uIHRvIHJvd25hbWVzCgojIGNyZWF0ZSBhIHZlY3RvciBzbyB0aGF0IGNvbCBuYW1lcyBpbiBhYnVuZGFuY2UgZGYgbWF0Y2hlcyBtZXRhZGF0YSBkZgpvcmRlcl9vdXRsaWVyc19mb3JQQ0F0b29scyA8LSBtYXRjaChyb3duYW1lcyhtZXRhZGF0YV9vdXRsaWVyc19mb3JQQ0F0b29scyksIGNvbG5hbWVzKGltcF9jbHVzdF9vbWljc2RhdGFfb3V0bGllcnNfZm9yUENBdG9vbHMpKQoKIyByZW9yZGVyIGNvbCBuYW1lcyBpbiBhYnVuZGFuY2UgZGYgc28gdGhhdCBpdCBtYXRjaGVzIG1ldGFkYXRhCmFidW5kYXRhX291dGxpZXJzX3Jlb3JkZXJlZF9mb3JQQ0F0b29scyA8LSBpbXBfY2x1c3Rfb21pY3NkYXRhX291dGxpZXJzX2ZvclBDQXRvb2xzWyAsb3JkZXJfb3V0bGllcnNfZm9yUENBdG9vbHNdIAoKIyBjaGFuZ2UgYWJ1bmRhbmNlIGRmIHRvIG51bWVyaWMgYW5kIGNoYW5nZSBuYW1lIHRvIGZvciBjb25zaXN0ZW5jeSEgKHVzaW5nIGRmIHRoYXQgaXMgYWxyZWFkeSBsb2cyIHRyYW5zZm9ybWVkIGFzIG9mIDgvMjYvMjQpCmxvZzJfYWJ1bmRhdGFfb3V0bGllcnNfcmVvcmRlcmVkX2ZvclBDQXRvb2xzIDwtCiAgYWJ1bmRhdGFfb3V0bGllcnNfcmVvcmRlcmVkX2ZvclBDQXRvb2xzICU+JQogIG11dGF0ZV9hbGwoYXMubnVtZXJpYykKCgojIHVuaXRlIHByZV9wb3N0IGNvbHVtbiB3aXRoIGludGVydmVudGlvbiBjb2x1bW4gdG8gY3JlYXRlIHByZV9pbnRlcnZlbnRpb24gY29sdW1uCm1ldGFkYXRhX291dGxpZXJzX2ZvclBDQXRvb2xzIDwtIG1ldGFkYXRhX291dGxpZXJzX2ZvclBDQXRvb2xzICU+JQogIHVuaXRlKGNvbCA9ICJwcmVfcG9zdF9pbnRlcnZlbnRpb24iLAogICAgICAgIGMoInByZV9wb3N0IiwiSW50ZXJ2ZW50aW9uIiksCiAgICAgICAgc2VwID0gIl8iLAogICAgICAgIHJlbW92ZSA9IEZBTFNFKQpgYGAKCiMjIyBQQ0EKYGBge3IsIGZpZy53aWR0aD03LCBmaWcuaGVpZ2h0PTcuNX0KIyBwY2EKcF9vdXRsaWVycyA8LSBQQ0F0b29sczo6cGNhKGxvZzJfYWJ1bmRhdGFfb3V0bGllcnNfcmVvcmRlcmVkX2ZvclBDQXRvb2xzLCAKICAgICAgICAgbWV0YWRhdGEgPSBtZXRhZGF0YV9vdXRsaWVyc19mb3JQQ0F0b29scywgCiAgICAgICAgIHNjYWxlID0gRkFMU0UgIyB1c2luZyBzY2FsZWQgZGF0YSBhbHJlYWR5IChsb2cyIHRyYW5zZm9ybWVkKQogICAgICAgICAKKQpgYGAKCgojIyMgTW9yZSBQQ0FzCgojIyMjIFByZSB2cyBwb3N0IGJvdGgKCiMjIyMjIFBDMXZQQzIKCgpgYGB7ciwgZmlnLndpZHRoPTguNSwgZmlnLmhlaWdodD02LjV9CihQQ0F0b29sc19vdXRsaWVycyA8LSBiaXBsb3QocF9vdXRsaWVycywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYiA9IHBhc3RlMChtZXRhZGF0YV9vdXRsaWVyc19mb3JQQ0F0b29scyRTdWJqZWN0KSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sYnkgPSAncHJlX3Bvc3RfaW50ZXJ2ZW50aW9uJywKICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sa2V5ID0gYygicHJlX1llbGxvdyIgPSAibGVtb25jaGlmZm9uMSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicG9zdF9ZZWxsb3ciID0gInllbGxvdzIiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInByZV9SZWQiID0gInJvc3licm93bjIiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInBvc3RfUmVkIiA9ICJkYXJrcmVkIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGhsaW5lID0gMCwgdmxpbmUgPSAwLAogICAgICAgICAgICAgICAgICAgICAgICAgICBsZWdlbmRQb3NpdGlvbiA9ICdyaWdodCcsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHRpdGxlID0gIlBDQSBTY29yZXMgUGxvdCB3aXRoIExvYWRpbmdzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgc3VidGl0bGUgPSAiTG9nMiB0cmFuc2Zvcm1lZCBkYXRhLCBjMTggKCspLCB3aXRob3V0IFFDcyBidXQgd2l0aCBvdXRsaWVycyAvbjk5JSBDb25maWRlbmNlIEVsbGlwc2VzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgZWxsaXBzZSA9IFRSVUUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGVsbGlwc2VUeXBlID0gJ3QnLCAjIGFzc3VtZXMgbXVsdGl2YXJpYXRlCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGVsbGlwc2VMZXZlbCA9IDAuOTksCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGVsbGlwc2VGaWxsID0gVFJVRSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgZWxsaXBzZUFscGhhID0gMC4yLAogICAgICAgICAgICAgICAgICAgICAgICAgICBlbGxpcHNlTGluZVNpemUgPSAwLjUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHhsaW0gPSBjKC0xMCwgMTApLAogICAgICAgICAgICAgICAgICAgICAgICAgICB5bGltID0gYygtMTAsIDEwKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgc2hvd0xvYWRpbmdzID0gRkFMU0UpKQpgYGAKCjYxMDYgYW5kIDYxMTIgYXJlIG91dHNpZGUgb2YgdGhlIDk5JSBjb25maWRlbmNlIGludGVydmFsLCB3ZSB3aWxsIGNsYXNzaWZ5IHRoZW0gYXMgdHJ1ZSBvdXRsaWVycyBtb3ZpbmcgZm9yd2FyZC4KCiMjIE5vIG91dGxpZXJzCgojIyMgRGF0YSB3cmFuZ2xpbmcKYGBge3J9CiMgY3JlYXRlIHJlbCBhYnVuZCBkZiBzdWl0YWJsZSBmb3IgUENBdG9vbHMgcGFja2FnZQoKaW1wX2NsdXN0X29taWNzZGF0YV9mb3JQQ0F0b29scyA8LSBhcy5kYXRhLmZyYW1lKHQoYW5ub19pbXBfbWV0YWJpbmRfY2x1c3RfbG9nMlssLWMoMjoxMSldKSkgIyB0cmFuc3Bvc2UgZGYgCgpuYW1lcyhpbXBfY2x1c3Rfb21pY3NkYXRhX2ZvclBDQXRvb2xzKSA8LSBpbXBfY2x1c3Rfb21pY3NkYXRhX2ZvclBDQXRvb2xzWzEsXSAjIG1ha2Ugc2FtcGxlIElEcyBjb2x1bW4gbmFtZXMKCmltcF9jbHVzdF9vbWljc2RhdGFfZm9yUENBdG9vbHMgPC0gaW1wX2NsdXN0X29taWNzZGF0YV9mb3JQQ0F0b29sc1stMSxdICMgcmVtb3ZlIHNhbXBsZSBJRCByb3cKCmltcF9jbHVzdF9vbWljc2RhdGFfZm9yUENBdG9vbHMgPC0gaW1wX2NsdXN0X29taWNzZGF0YV9mb3JQQ0F0b29scyAlPiUKICBkcGx5cjo6c2VsZWN0KCFjb250YWlucygiUUMiKSkgIyByZW1vdmUgUUMgb2JzZXJ2YXRpb25zCgoKIyBjcmVhdGUgbWV0YWRhdGEgZGYgc3VpdGFibGUgZm9yIFBDQXRvb2xzIHBja2cKbWV0YWRhdGFfZm9yUENBdG9vbHMgPC0gbWV0YWRhdGEgJT4lCiAgY29sdW1uX3RvX3Jvd25hbWVzKHZhciA9ICJzYW1wbGVfSUQiKSAjIGNoYW5nZSBzYW1wbGUgSUQgY29sdW1uIHRvIHJvd25hbWVzCgojIGNyZWF0ZSBhIHZlY3RvciBzbyB0aGF0IGNvbCBuYW1lcyBpbiBhYnVuZGFuY2UgZGYgbWF0Y2hlcyBtZXRhZGF0YSBkZgpvcmRlcl9mb3JQQ0F0b29scyA8LSBtYXRjaChyb3duYW1lcyhtZXRhZGF0YV9mb3JQQ0F0b29scyksIGNvbG5hbWVzKGltcF9jbHVzdF9vbWljc2RhdGFfZm9yUENBdG9vbHMpKQoKIyByZW9yZGVyIGNvbCBuYW1lcyBpbiBhYnVuZGFuY2UgZGYgc28gdGhhdCBpdCBtYXRjaGVzIG1ldGFkYXRhCmFidW5kYXRhX3Jlb3JkZXJlZF9mb3JQQ0F0b29scyA8LSBpbXBfY2x1c3Rfb21pY3NkYXRhX2ZvclBDQXRvb2xzWyAsb3JkZXJfZm9yUENBdG9vbHNdIAoKIyBjaGFuZ2UgYWJ1bmRhbmNlIGRmIHRvIG51bWVyaWMKbG9nMl9hYnVuZGF0YV9yZW9yZGVyZWRfZm9yUENBdG9vbHMgPC0gYWJ1bmRhdGFfcmVvcmRlcmVkX2ZvclBDQXRvb2xzICU+JQogIG11dGF0ZV9hdCgxOm5jb2woLiksIGFzLm51bWVyaWMpCgojIGZpeCByb3duYW1lcyB0byBoYXZlIGtleXMgYWdhaW4Kcm93bmFtZXMobG9nMl9hYnVuZGF0YV9yZW9yZGVyZWRfZm9yUENBdG9vbHMpIDwtIHJvd25hbWVzKGFidW5kYXRhX3Jlb3JkZXJlZF9mb3JQQ0F0b29scykKCiMgcmVtb3ZlIG91dGxpZXIgc3ViaiBmcm9tIGJvdGggZGYKbG9nMl9hYnVuZGF0YV9mb3JQQ0F0b29scyA8LSBsb2cyX2FidW5kYXRhX3Jlb3JkZXJlZF9mb3JQQ0F0b29scyAlPiUKICBkcGx5cjo6c2VsZWN0KCFjb250YWlucygiNjEwNiIpKSAlPiUKICBkcGx5cjo6c2VsZWN0KCFjb250YWlucygiNjExMiIpKQoKbWV0YWRhdGFfZm9yUENBdG9vbHMgPC0gbWV0YWRhdGFfZm9yUENBdG9vbHMgJT4lCiAgZmlsdGVyKFN1YmplY3QgIT0gNjEwNiwKICAgICAgICAgU3ViamVjdCAhPSA2MTEyKQoKIyB1bml0ZSBwcmVfcG9zdCBjb2x1bW4gd2l0aCBpbnRlcnZlbnRpb24gY29sdW1uIHRvIGNyZWF0ZSBwcmVfaW50ZXJ2ZW50aW9uIGNvbHVtbgptZXRhZGF0YV9mb3JQQ0F0b29scyA8LSBtZXRhZGF0YV9mb3JQQ0F0b29scyAlPiUKICB1bml0ZShjb2wgPSAicHJlX3Bvc3RfaW50ZXJ2ZW50aW9uIiwKICAgICAgICBjKCJwcmVfcG9zdCIsIkludGVydmVudGlvbiIpLAogICAgICAgIHNlcCA9ICJfIiwKICAgICAgICByZW1vdmUgPSBGQUxTRSkKCmBgYAoKCiMjIyBTY3JlZXBsb3QgYW5hbHlzaXMKCkhvcm4ncyBwYXJhbGxlbCBhbmFseXNpcwpgYGB7ciwgd2FybmluZz1GQUxTRX0KaG9ybiA8LSBwYXJhbGxlbFBDQShsb2cyX2FidW5kYXRhX2ZvclBDQXRvb2xzKQoKaG9ybiRuCmBgYAoKYGBge3IsIGZpZy53aWR0aD03LCBmaWcuaGVpZ2h0PTcuNX0KIyBwY2EKcCA8LSBQQ0F0b29sczo6cGNhKGxvZzJfYWJ1bmRhdGFfZm9yUENBdG9vbHMsIAogICAgICAgICBtZXRhZGF0YSA9IG1ldGFkYXRhX2ZvclBDQXRvb2xzLCAKICAgICAgICAgc2NhbGUgPSBGQUxTRSAjIHVzaW5nIHNjYWxlZCBkYXRhIGFscmVhZHkgKGxvZzIgdHJhbnNmb3JtZWQpCiAgICAgICAgIAopCmBgYAoKRWxib3cgbWV0aG9kCmBgYHtyfQplbGJvdyA8LSBmaW5kRWxib3dQb2ludChwJHZhcmlhbmNlKQoKZWxib3cKYGBgCgoKYGBge3J9CiAgc2NyZWVwbG90KHAsCiAgICBjb21wb25lbnRzID0gZ2V0Q29tcG9uZW50cyhwLCAxOjIwKSwKICAgIHZsaW5lID0gYyhob3JuJG4sIGVsYm93KSkgKwogIGdlb21fbGFiZWwoYWVzKHggPSBob3JuJG4gKyAxLCB5ID0gNTAsCiAgICAgIGxhYmVsID0gJ0hvcm5cJ3MnLCB2anVzdCA9IC0xLCBzaXplID0gOCkpICsKICAgIGdlb21fbGFiZWwoYWVzKHggPSBlbGJvdyArIDEsIHkgPSA1MCwKICAgICAgbGFiZWwgPSAnRWxib3cgbWV0aG9kJywgdmp1c3QgPSAtMywgc2l6ZSA9IDgpKQpgYGAKCkhvdyBtYW55IFBDcyBkbyB3ZSBuZWVkIHRvIGNhcHR1cmUgYXQgbGVhc3QgODAlIHZhcmlhbmNlPwpgYGB7cn0Kd2hpY2goY3Vtc3VtKHAkdmFyaWFuY2UpID4gODApWzFdCmBgYAoKIyMjIE1vcmUgUENBcwoKIyMjIyBQcmUgdnMgcG9zdCBib3RoCgojIyMjIyBQQzF2UEMyCgoKYGBge3IsICBmaWcud2lkdGg9OH0KYmlwbG90KHAsCiAgICAgICBsYWIgPSBwYXN0ZTAobWV0YWRhdGFfZm9yUENBdG9vbHMkU3ViamVjdCksCiAgICAgICAgICBjb2xieSA9ICdwcmVfcG9zdF9pbnRlcnZlbnRpb24nLAogICAgICAgICAgY29sa2V5ID0gYygicHJlX1llbGxvdyIgPSAibGVtb25jaGlmZm9uMSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicG9zdF9ZZWxsb3ciID0gInllbGxvdzIiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInByZV9SZWQiID0gInJvc3licm93bjIiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInBvc3RfUmVkIiA9ICJkYXJrcmVkIiksCiAgICAgICAgIGNvbExlZ2VuZFRpdGxlID0gIkludGVydmVudGlvbiBUaW1lcG9pbnQiLAogICAgICAgICAjIGVsbGlwc2UgY29uZmlnCiAgICAgICAgIGVsbGlwc2UgPSBUUlVFLAogICAgICAgICBlbGxpcHNlVHlwZSA9ICd0JywKICAgICAgICAgZWxsaXBzZUxldmVsID0gMC45OSwKICAgICAgICAgZWxsaXBzZUZpbGwgPSBUUlVFLAogICAgICAgICBlbGxpcHNlQWxwaGEgPSAwLjIsCiAgICAgICAgIGVsbGlwc2VMaW5lU2l6ZSA9IDEuMCwKICAgICAgICAgeGxpbSA9IGMoLTEwLDEwKSwgeWxpbSA9IGMoLTEwLCAxMCksCiAgICAgICAgIGhsaW5lID0gMCwgdmxpbmUgPSAwLAogICAgICAgbGVnZW5kUG9zaXRpb24gPSAncmlnaHQnLAogICAgICAgdGl0bGUgPSAiUENBIFNjb3JlcyBQbG90IiwKICAgICAgIHN1YnRpdGxlID0gIkxvZzIgdHJhbnNmb3JtZWQgZGF0YSwgYzE4ICgrKSwgb3V0bGllcnMgNjEwNiBhbmQgNjExMiByZW1vdmVkLCBubyBRQ3MgXG45OSUgY29uZmlkZW5jZSBsZXZlbCBlbGxpcHNlcyIpCgpgYGAKCgpgYGB7ciwgZmlnLndpZHRoPTguNSwgZmlnLmhlaWdodD02LjV9CihQQ0EuY29sYnkucHJldnNwb3N0IDwtIGJpcGxvdChwLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFiID0gTlVMTCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sYnkgPSAncHJlX3Bvc3RfaW50ZXJ2ZW50aW9uJywKICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sa2V5ID0gYygicHJlX1llbGxvdyIgPSAibGVtb25jaGlmZm9uMSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicG9zdF9ZZWxsb3ciID0gInllbGxvdzIiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInByZV9SZWQiID0gInJvc3licm93bjIiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInBvc3RfUmVkIiA9ICJkYXJrcmVkIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGhsaW5lID0gMCwgdmxpbmUgPSAwLAogICAgICAgICBsZWdlbmRQb3NpdGlvbiA9ICdyaWdodCcsCiAgICAgICAgIHRpdGxlID0gIlBDQSBTY29yZXMgUGxvdCIsCiAgICAgICAgIHN1YnRpdGxlID0gIkxvZzIgdHJhbnNmb3JtZWQgZGF0YSwgYzE4ICgrKSwgb3V0bGllcnMgNjEwNiBhbmQgNjExMiByZW1vdmVkLCBubyBRQ3MiLAogICAgICAgICBzaG93TG9hZGluZ3MgPSBGKSApCgpgYGAKCmBgYHtyLCBmaWcud2lkdGg9OC41LCBmaWcuaGVpZ2h0PTYuNX0KYmlwbG90KHAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYWIgPSBOVUxMLAogICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xieSA9ICdwcmVfcG9zdF9pbnRlcnZlbnRpb24nLAogICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xrZXkgPSBjKCJwcmVfWWVsbG93IiA9ICJsZW1vbmNoaWZmb24xIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJwb3N0X1llbGxvdyIgPSAieWVsbG93MiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicHJlX1JlZCIgPSAicm9zeWJyb3duMiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicG9zdF9SZWQiID0gImRhcmtyZWQiKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgaGxpbmUgPSAwLCB2bGluZSA9IDAsCiAgICAgICAgIGxlZ2VuZFBvc2l0aW9uID0gJ3JpZ2h0JywKICAgICAgICAgdGl0bGUgPSAiUENBIFNjb3JlcyBQbG90IiwKICAgICAgICAgc3VidGl0bGUgPSAiTG9nMiB0cmFuc2Zvcm1lZCBkYXRhLCBjMTggKCspLCBvdXRsaWVycyA2MTA2IGFuZCA2MTEyIHJlbW92ZWQsIG5vIFFDcyIsCiAgICAgICAgIHNob3dMb2FkaW5ncyA9IFQpCgpgYGAKCiMjIyMjIFBhaXJzIHBsb3QKYGBge3IsIGZpZy53aWR0aD0xMCwgZmlnLmhlaWdodD0xMCwgbWVzc2FnZT1GQUxTRX0KKFBDQV9wYWlyc3Bsb3QuY29sYnkucHJldnNwb3N0IDwtCiAgcGFpcnNwbG90KHAsCiAgICBjb21wb25lbnRzID0gZ2V0Q29tcG9uZW50cyhwLCBjKDE6MTApKSwKICAgIHRyaWFuZ2xlID0gVFJVRSwgdHJpYW5nbGVsYWJTaXplID0gMTIsCiAgICBobGluZSA9IDAsIHZsaW5lID0gMCwKICAgIHBvaW50U2l6ZSA9IDAuNCwKICAgIGdyaWRsaW5lcy5tYWpvciA9IEZBTFNFLCBncmlkbGluZXMubWlub3IgPSBGQUxTRSwKICAgIGNvbGJ5ID0gJ3ByZV9wb3N0X2ludGVydmVudGlvbicsIAogICAgY29sa2V5ID0gYygicHJlX1llbGxvdyIgPSAibGVtb25jaGlmZm9uMSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicG9zdF9ZZWxsb3ciID0gInllbGxvdzIiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInByZV9SZWQiID0gInJvc3licm93bjIiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInBvc3RfUmVkIiA9ICJkYXJrcmVkIiksCiAgICB0aXRsZSA9ICdQYWlycyBwbG90JywgcGxvdGF4ZXMgPSBGQUxTRSwKICAgIG1hcmdpbmdhcHMgPSB1bml0KGMoLTAuMDEsIC0wLjAxLCAtMC4wMSwgLTAuMDEpLCAnY20nKSkpCgpgYGAKCiMjIyBTZXgKCiMjIyMgUEMxdlBDMgpgYGB7ciwgZmlnLndpZHRoPTh9CihQQ0EuY29sYnkuU2V4IDwtIGJpcGxvdChwLAogICAgICAgICAgICAgICAgICAgICAgICAgICBsYWIgPSBwYXN0ZTAobWV0YWRhdGFfZm9yUENBdG9vbHMkU3ViamVjdCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgY29sYnkgPSAnU2V4JywKICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xrZXkgPSBjKCJNIiA9ICJyZWQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkYiID0gInB1cnBsZSIpLAogICAgICAgICAgICAgICAgICAgICAgICAgIGhsaW5lID0gMCwgdmxpbmUgPSAwLAogICAgICAgICAgICAgICAgICAgICAgICAgIGxlZ2VuZFBvc2l0aW9uID0gJ3JpZ2h0JyArCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZW9tX3BvaW50KGFlcyh0ZXh0ID0gbWV0YWRhdGFfZm9yUENBdG9vbHMkU3ViamVjdCkpKSkKCmdncGxvdGx5KFBDQS5jb2xieS5TZXgsCiAgICAgICAgIHRvb2x0aXAgPSAidGV4dCIpIAoKYGBgCgojIyMjIFBhaXJzcGxvdApgYGB7ciwgZmlnLndpZHRoPTEwLCBmaWcuaGVpZ2h0PTEwLCBtZXNzYWdlPUZBTFNFfQogIHBhaXJzcGxvdChwLAogICAgY29tcG9uZW50cyA9IGdldENvbXBvbmVudHMocCwgYygxOjEwKSksCiAgICB0cmlhbmdsZSA9IFRSVUUsIHRyaWFuZ2xlbGFiU2l6ZSA9IDEyLAogICAgaGxpbmUgPSAwLCB2bGluZSA9IDAsCiAgICBwb2ludFNpemUgPSAwLjQsCiAgICBncmlkbGluZXMubWFqb3IgPSBGQUxTRSwgZ3JpZGxpbmVzLm1pbm9yID0gRkFMU0UsCiAgICBjb2xieSA9ICdTZXgnLCAKICAgIGNvbGtleSA9IGMoIk0iID0gInJlZCIsCiAgICAgICAgICAgICAgICJGIiA9ICJwdXJwbGUiKSwKICAgIHRpdGxlID0gJ1BhaXJzIHBsb3QnLCBwbG90YXhlcyA9IEZBTFNFLAogICAgbWFyZ2luZ2FwcyA9IHVuaXQoYygtMC4wMSwgLTAuMDEsIC0wLjAxLCAtMC4wMSksICdjbScpKQpgYGAKCgojIyMgUHJlIHZzIHBvc3QgdG9tYXRvCgojIyMjIFBDMXZQQzIKYGBge3IsIGZpZy53aWR0aD04LCBmaWcuaGVpZ2h0PTYuNSwgbWVzc2FnZT1GQUxTRX0KKFBDQS5jb2xieS5vdmVyYWxsLnByZXZzcG9zdCA8LSBiaXBsb3QocCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFiID0gcGFzdGUwKG1ldGFkYXRhX2ZvclBDQXRvb2xzJFN1YmplY3QpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xieSA9ICdwcmVfcG9zdCcsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbGtleSA9IGMoInByZSIgPSAiZ3JheSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInBvc3QiID0gImRhcmtncmVlbiIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBobGluZSA9IDAsIHZsaW5lID0gMCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGVnZW5kUG9zaXRpb24gPSAncmlnaHQnICsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZW9tX3BvaW50KGFlcyh0ZXh0ID0gbWV0YWRhdGFfZm9yUENBdG9vbHMkU3ViamVjdCkpKSkKCmdncGxvdGx5KFBDQS5jb2xieS5vdmVyYWxsLnByZXZzcG9zdCwKICAgICAgICAgdG9vbHRpcCA9ICJ0ZXh0IikgCgpgYGAKCiMjIyMgUGFpcnNwbG90CgpgYGB7ciwgZmlnLndpZHRoPTEwLCBmaWcuaGVpZ2h0PTEwLCBtZXNzYWdlPUZBTFNFfQogIHBhaXJzcGxvdChwLAogICAgY29tcG9uZW50cyA9IGdldENvbXBvbmVudHMocCwgYygxOjEwKSksCiAgICB0cmlhbmdsZSA9IFRSVUUsIHRyaWFuZ2xlbGFiU2l6ZSA9IDEyLAogICAgaGxpbmUgPSAwLCB2bGluZSA9IDAsCiAgICBwb2ludFNpemUgPSAwLjQsCiAgICBncmlkbGluZXMubWFqb3IgPSBGQUxTRSwgZ3JpZGxpbmVzLm1pbm9yID0gRkFMU0UsCiAgICBjb2xieSA9ICdwcmVfcG9zdCcsIAogICAgY29sa2V5ID0gYygicHJlIiA9ICJncmF5IiwKICAgICAgICAgICAgICAgInBvc3QiID0gImRhcmtncmVlbiIpLAogICAgdGl0bGUgPSAnUGFpcnMgcGxvdCcsIHBsb3RheGVzID0gRkFMU0UsCiAgICBtYXJnaW5nYXBzID0gdW5pdChjKC0wLjAxLCAtMC4wMSwgLTAuMDEsIC0wLjAxKSwgJ2NtJykpCmBgYAoKCiMjIyBQZXJpb2QKCkhlcmUgaXMgYSBnb29kIGNoZWNrIGZvciBhbnkgcGVyaW9kIGVmZmVjdHMKCiMjIyMgUEMxdlBDMgpgYGB7ciwgZmlnLndpZHRoPTgsIGZpZy5oZWlnaHQ9Ni41LCBtZXNzYWdlPUZBTFNFfQooUENBLmNvbGJ5LnBlcmlvZCA8LSBiaXBsb3QocCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYiA9IHBhc3RlMChtZXRhZGF0YV9mb3JQQ0F0b29scyRTdWJqZWN0KSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbGJ5ID0gJ1BlcmlvZCcsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBobGluZSA9IDAsIHZsaW5lID0gMCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxlZ2VuZFBvc2l0aW9uID0gJ3JpZ2h0JyArCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdlb21fcG9pbnQoYWVzKHRleHQgPSBtZXRhZGF0YV9mb3JQQ0F0b29scyRTdWJqZWN0KSkpKQoKZ2dwbG90bHkoUENBLmNvbGJ5LnBlcmlvZCwKICAgICAgICAgdG9vbHRpcCA9ICJ0ZXh0IikgCgpgYGAKCiMjIyMgUGFpcnNwbG90CmBgYHtyLCBmaWcud2lkdGg9MTAsIGZpZy5oZWlnaHQ9MTAsIG1lc3NhZ2U9RkFMU0V9CiAgcGFpcnNwbG90KHAsCiAgICBjb21wb25lbnRzID0gZ2V0Q29tcG9uZW50cyhwLCBjKDE6MTApKSwKICAgIHRyaWFuZ2xlID0gVFJVRSwgdHJpYW5nbGVsYWJTaXplID0gMTIsCiAgICBobGluZSA9IDAsIHZsaW5lID0gMCwKICAgIHBvaW50U2l6ZSA9IDAuNCwKICAgIGdyaWRsaW5lcy5tYWpvciA9IEZBTFNFLCBncmlkbGluZXMubWlub3IgPSBGQUxTRSwKICAgIGNvbGJ5ID0gJ1BlcmlvZCcsCiAgICB0aXRsZSA9ICdQYWlycyBwbG90JywgcGxvdGF4ZXMgPSBGQUxTRSwKICAgIG1hcmdpbmdhcHMgPSB1bml0KGMoLTAuMDEsIC0wLjAxLCAtMC4wMSwgLTAuMDEpLCAnY20nKSkKYGBgCgoKCiMjIyBTZXF1ZW5jZQoKQWxzbyBsb29raW5nIGZvciBzZXF1ZW5jZSBlZmZlY3RzCgojIyMjIFBDMXZQQzIKYGBge3IsIGZpZy53aWR0aD04LCBmaWcuaGVpZ2h0PTYuNSwgbWVzc2FnZT1GQUxTRX0KKFBDQS5jb2xieS5zZXF1ZW5jZSA8LSBiaXBsb3QocCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYiA9IHBhc3RlMChtZXRhZGF0YV9mb3JQQ0F0b29scyRTdWJqZWN0KSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbGJ5ID0gJ3NlcXVlbmNlJywKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGhsaW5lID0gMCwgdmxpbmUgPSAwLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgbGVnZW5kUG9zaXRpb24gPSAncmlnaHQnICsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2VvbV9wb2ludChhZXModGV4dCA9IG1ldGFkYXRhX2ZvclBDQXRvb2xzJFN1YmplY3QpKSkpCgpnZ3Bsb3RseShQQ0EuY29sYnkuc2VxdWVuY2UsCiAgICAgICAgIHRvb2x0aXAgPSAidGV4dCIpIAoKYGBgCgojIyMjIFBhaXJzcGxvdApgYGB7ciwgZmlnLndpZHRoPTEwLCBmaWcuaGVpZ2h0PTEwLCBtZXNzYWdlPUZBTFNFfQogIHBhaXJzcGxvdChwLAogICAgY29tcG9uZW50cyA9IGdldENvbXBvbmVudHMocCwgYygxOjEwKSksCiAgICB0cmlhbmdsZSA9IFRSVUUsIHRyaWFuZ2xlbGFiU2l6ZSA9IDEyLAogICAgaGxpbmUgPSAwLCB2bGluZSA9IDAsCiAgICBwb2ludFNpemUgPSAwLjQsCiAgICBncmlkbGluZXMubWFqb3IgPSBGQUxTRSwgZ3JpZGxpbmVzLm1pbm9yID0gRkFMU0UsCiAgICBjb2xieSA9ICdzZXF1ZW5jZScsCiAgICB0aXRsZSA9ICdQYWlycyBwbG90JywgcGxvdGF4ZXMgPSBGQUxTRSwKICAgIG1hcmdpbmdhcHMgPSB1bml0KGMoLTAuMDEsIC0wLjAxLCAtMC4wMSwgLTAuMDEpLCAnY20nKSkKYGBgCgojIyBFaWdlbiBjb3JwbG90cwpUaGlzIGlzIGEgY29vbCB3YXkgdG8gZXhwbG9yZSB0aGUgY29ycmVsYXRpb25zIGJldHdlZW4gdGhlIG1ldGFkYXRhIGFuZCB0aGUgUENzISBJIHdhbnQgdG8gbG9vayBhdCBob3cgdGhlIG1ldGF2YXJpYWJsZXMgY29ycmVsYXRlIHdpdGggUENzIHRoYXQgYWNjb3VudCBmb3IgODAlIHZhcmlhdGlvbiBpbiB0aGUgZGF0YXNldC4gCgpBZ2FpbjogSG93IG1hbnkgUENzIGRvIHdlIG5lZWQgdG8gY2FwdHVyZSBhdCBsZWFzdCA4MCUgdmFyaWFuY2U/CmBgYHtyfQp3aGljaChjdW1zdW0ocCR2YXJpYW5jZSkgPiA4MClbMV0KYGBgCgpgYGB7ciwgZmlnLndpZHRoPTEyLCBmaWcuaGVpZ2h0PTcuNSwgbWVzc2FnZT1GQUxTRX0KCiAgZWlnZW5jb3JwbG90KHAsCiAgICBjb21wb25lbnRzID0gZ2V0Q29tcG9uZW50cyhwLCAxOjE2KSwgIyBnZXQgY29tcG9uZW50cyB0aGF0IGFjY291bnQgZm9yIDgwJSB2YXJpYW5jZQogICAgbWV0YXZhcnMgPSBjb2xuYW1lcyhtZXRhZGF0YV9mb3JQQ0F0b29scyksCiAgICBjb2wgPSBjKCdkYXJrYmx1ZScsICdibHVlMicsICdncmF5JywgJ3JlZDInLCAnZGFya3JlZCcpLAogICAgY2V4Q29ydmFsID0gMC43LAogICAgY29sQ29ydmFsID0gJ3doaXRlJywKICAgIGZvbnRDb3J2YWwgPSAyLAogICAgcG9zTGFiID0gJ2JvdHRvbWxlZnQnLAogICAgcm90TGFiWCA9IDQ1LAogICAgcG9zQ29sS2V5ID0gJ3RvcCcsCiAgICBjZXhMYWJDb2xLZXkgPSAxLjUsCiAgICBzY2FsZSA9IFRSVUUsCiAgICBtYWluID0gJ1BDMS0xNCBtZXRhZGF0YSBjb3JyZWxhdGlvbnMnLAogICAgY29sRnJhbWUgPSAnd2hpdGUnLAogICAgcGxvdFJzcXVhcmVkID0gRkFMU0UpCgoKYGBgCgoKYGBge3IsIGZpZy53aWR0aD0xNSwgZmlnLmhlaWdodD03LjUsIG1lc3NhZ2U9RkFMU0V9CiAgZWlnZW5jb3JwbG90KHAsCiAgICBjb21wb25lbnRzID0gZ2V0Q29tcG9uZW50cyhwLCAxOjE2KSwKICAgIG1ldGF2YXJzID0gY29sbmFtZXMobWV0YWRhdGFfZm9yUENBdG9vbHMpLAogICAgY29sID0gYygnd2hpdGUnLCAnY29ybnNpbGsxJywgJ2dvbGQnLCAnZm9yZXN0Z3JlZW4nLCAnZGFya2dyZWVuJyksCiAgICBjZXhDb3J2YWwgPSAxLjIsCiAgICBmb250Q29ydmFsID0gMiwKICAgIHBvc0xhYiA9ICdhbGwnLAogICAgcm90TGFiWCA9IDQ1LAogICAgc2NhbGUgPSBUUlVFLAogICAgbWFpbiA9IGJxdW90ZShQcmluY2lwYWwgfiBjb21wb25lbnQgfiBQZWFyc29uIH4gcl4yIH4gbWV0YWRhdGEgfiBjb3JyZWxhdGVzKSwKICAgIHBsb3RSc3F1YXJlZCA9IFRSVUUsCiAgICBjb3JGVU4gPSAncGVhcnNvbicsCiAgICBjb3JVU0UgPSAncGFpcndpc2UuY29tcGxldGUub2JzJywKICAgIGNvck11bHRpcGxlVGVzdENvcnJlY3Rpb24gPSAnQkgnLAogICAgc2lnbmlmU3ltYm9scyA9IGMoJyoqKionLCAnKioqJywgJyoqJywgJyonLCAnJyksCiAgICBzaWduaWZDdXRwb2ludHMgPSBjKDAsIDAuMDAwMSwgMC4wMDEsIDAuMDEsIDAuMDUsIDEpKQpgYGAKCgpJIGFtIG1vc3QgaW50ZXJlc3RlZCBpbiBQQ3MgYWZmZWN0ZWQgYnkgcHJlX3Bvc3RfaW50ZXJ2ZW50aW9uLCBzbyBJIHRoaW5rIGl0IHdvdWxkIGJlIGdvb2QgdG8gaW52ZXN0aWdhdGUgdGhlIG1ldGFib2xpdGVzIHRoYXQgY29udHJpYnV0ZSB0aGUgbW9zdCB0byB0aGVzZSBQQ3MuCgojIyBMb2FkaW5ncyBwbG90cwoKIyMjIFBDNy9QQzgKYGBge3IsIGZpZy53aWR0aD0xMCwgZmlnLmhlaWdodD0xMH0KIyBsb2FkaW5ncyBwbG90IGZvciBQQ3MgNyBhbmQgOAogIHBsb3Rsb2FkaW5ncyhwLAogICAgY29tcG9uZW50cyA9IGdldENvbXBvbmVudHMocCwgYyg3LDgpKSwKICAgIHJhbmdlUmV0YWluID0gMC4xLCBhYnNvbHV0ZSA9IFRSVUUsCiAgICBjb2wgPSBjKCdibGFjaycsICdwaW5rJywgJ3JlZDQnKSwKICAgIGRyYXdDb25uZWN0b3JzID0gVFJVRSwgbGFiU2l6ZSA9IDMsCiAgICB0aXRsZSA9ICJMb2FkaW5ncyBwbG90IiwKICAgIHN1YnRpdGxlID0gIlBDIDcgYW5kIFBDIDgiLAogICAgY2FwdGlvbiA9ICJQcmVfcG9zdF9pbnRlcnZlbnRpb24gaXMgc3Ryb25nbHkgY29ycmVsYXRlZCB3aXRoIHRoZXNlIFBDcyB3aXRob3V0IG11bHRpcGxlIHRlc3RpbmcgY29ycmVjdGlvbiIpCmBgYAoKIyMjIyBTY29yZXMgYmlwbG90CmBgYHtyLCBmaWcud2lkdGg9OCwgZmlnLmhlaWdodD02fQpiaXBsb3QocCwKICAgICAgIGxhYiA9IE5VTEwsCiAgICAgICB4ID0gIlBDNyIsCiAgICAgICB5ID0gIlBDOCIsCiAgICAgICBjb2xieSA9ICdwcmVfcG9zdF9pbnRlcnZlbnRpb24nLAogICAgICAgY29sa2V5ID0gYygicHJlX1llbGxvdyIgPSAibGVtb25jaGlmZm9uMSIsCiAgICAgICAgICAgICAgICAgICJwb3N0X1llbGxvdyIgPSAieWVsbG93MiIsCiAgICAgICAgICAgICAgICAgICJwcmVfUmVkIiA9ICJyb3N5YnJvd24yIiwKICAgICAgICAgICAgICAgICAgInBvc3RfUmVkIiA9ICJkYXJrcmVkIiksCiAgICAgICBjb2xMZWdlbmRUaXRsZSA9ICJJbnRlcnZlbnRpb24gVGltZXBvaW50IiwKICAgICAgIGhsaW5lID0gMCwgdmxpbmUgPSAwLAogICAgICAgbGVnZW5kUG9zaXRpb24gPSAncmlnaHQnLAogICAgICAgdGl0bGUgPSAiUENBIFNjb3JlcyBQbG90IiwKICAgICAgIHN1YnRpdGxlID0gIkxvZzIgdHJhbnNmb3JtZWQgZGF0YSwgYzE4ICgrKSwgb3V0bGllcnMgcmVtb3ZlZCwgbm8gUUNzIFxuOTUlIGNvbmZpZGVuY2UgbGV2ZWwgZWxsaXBzZXMiLAogICAgICAgc2hvd0xvYWRpbmdzID0gVFJVRSkKYGBgCgoKIyBNdWx0aWxldmVsIFBDQQoKCmBgYHtyfQoKRGF0YV9mb3JNUENBIDwtIGFubm9faW1wX21ldGFiaW5kX2NsdXN0X2xvZzJfbm9RQ3MgJT4lCiAgbXV0YXRlX2F0KCJTdWJqZWN0IiwgYXMuZmFjdG9yKQoKc3VtbWFyeShhcy5mYWN0b3IoRGF0YV9mb3JNUENBJFN1YmplY3QpKQoKIyBtYWtlIGEgdmVjdG9yIGZvciBtZXRhIHZhcmlhYmxlcwoobWV0YXZhciA8LSBEYXRhX2Zvck1QQ0FbLGMoMToxMSldICU+JQogICAgY29sbmFtZXMoKSkKYGBgCgoKCiMjIFJlZ3VsYXIgUENBCgpSZW1vdmUgcG9zdC1yZWQgZm9yIDYxMTIKYGBge3J9CkRhdGFfZm9yTVBDQV9ubzYxMTJwb3N0UmVkIDwtIERhdGFfZm9yTVBDQSAlPiUKICBmaWx0ZXIoISgoU3ViamVjdCA9PSA2MTEyKSAmIHByZV9wb3N0X2ludGVydmVudGlvbiA9PSAicG9zdF9SZWQiKSkKYGBgCgoKYGBge3J9Cm1peE9taWNzUENBLnJlc3VsdCA8LSBtaXhPbWljczo6cGNhKERhdGFfZm9yTVBDQV9ubzYxMTJwb3N0UmVkWywhbmFtZXMoRGF0YV9mb3JNUENBX25vNjExMnBvc3RSZWQpICVpbiUgbWV0YXZhcl0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBzY2FsZSA9IEZBTFNFLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgY2VudGVyID0gVCkKCnBsb3RJbmRpdihtaXhPbWljc1BDQS5yZXN1bHQsIAogICAgICAgICAgaW5kLm5hbWVzID0gRGF0YV9mb3JNUENBX25vNjExMnBvc3RSZWQkU3ViamVjdCwgCiAgICAgICAgICBncm91cCA9IERhdGFfZm9yTVBDQV9ubzYxMTJwb3N0UmVkJHByZV9wb3N0X2ludGVydmVudGlvbiwgCiAgICAgICAgICBjb2wucGVyLmdyb3VwID0gYygicG9zdF9SZWQiID0gImRhcmtyZWQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgInBvc3RfWWVsbG93IiA9ICJ5ZWxsb3czIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICJwcmVfUmVkIiA9ICJyb3N5YnJvd24iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgInBvc3RfWWVsbG93IiA9ICJsZW1vbmNoaWZmb24yIiksCiAgICAgICAgICBsZWdlbmQudGl0bGUgID0gIkludGVydmVudGlvbiBUaW1lcG9pbnQiLAogICAgICAgICAgbGVnZW5kID0gVFJVRSwgCiAgICAgICAgICB0aXRsZSA9ICdSZWd1bGFyIFBDQSwgYzE4ICgrKSwgTG9nMiB0cmFuc2Zvcm1lZCcpCgpgYGAKCgojIyBNdWx0aWxldmVsIFBDQQoKCgojIyMgcHJlX3Bvc3RfaW50ZXJ2ZW50aW9uCmBgYHtyfQptdWx0aWxldmVsUENBLnJlc3VsdCA8LSBtaXhPbWljczo6cGNhKERhdGFfZm9yTVBDQV9ubzYxMTJwb3N0UmVkWywtKGMoMToxMSkpXSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBtdWx0aWxldmVsID0gRGF0YV9mb3JNUENBX25vNjExMnBvc3RSZWQkU3ViamVjdCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNjYWxlID0gRkFMU0UsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjZW50ZXIgPSBUUlVFKQoKYGBgCgpgYGB7cn0KcGxvdEluZGl2KG11bHRpbGV2ZWxQQ0EucmVzdWx0LCAKICAgICAgICAgIGluZC5uYW1lcyA9IERhdGFfZm9yTVBDQV9ubzYxMTJwb3N0UmVkJFN1YmplY3QsIAogICAgICAgICAgZ3JvdXAgPSBEYXRhX2Zvck1QQ0Ffbm82MTEycG9zdFJlZCRwcmVfcG9zdF9pbnRlcnZlbnRpb24sIAogICAgICAgICAgY29sLnBlci5ncm91cCA9IGMoInBvc3RfUmVkIiA9ICJkYXJrcmVkIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICJwb3N0X1llbGxvdyIgPSAieWVsbG93MyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAicHJlX1JlZCIgPSAicm9zeWJyb3duIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICJwb3N0X1llbGxvdyIgPSAibGVtb25jaGlmZm9uMiIpLAogICAgICAgICAgbGVnZW5kID0gVFJVRSwgCiAgICAgICAgICBsZWdlbmQudGl0bGUgPSAiSW50ZXJ2ZW50aW9uIFRpbWVwb2ludCIsIAogICAgICAgICAgdGl0bGUgPSAnTXVsdGlsZXZlbCBQQ0EsIGMxOCAoKyksIExvZzIgdHJhbnNmb3JtZWQnKQpgYGAKCgojIyMjIExvYWRpbmdzIApgYGB7ciwgZmlnLndpZHRoPTEwfQoobG9hZGluZ3NfbXVsdGlsZXZlbFBDMSA8LSBwbG90TG9hZGluZ3MobXVsdGlsZXZlbFBDQS5yZXN1bHQsIGNvbXAgPSAxLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmRpc3BsYXkgPSAxNSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRpdGxlID0gIlRvcCAxNSBmZWF0dXJlcyBvbiBNdWx0aWxldmVsIFBDMSwgYzE4ICgrKSIpKQpgYGAKCmBgYHtyLCBmaWcud2lkdGg9MTB9Cihsb2FkaW5nc19tdWx0aWxldmVsUEMyIDwtIHBsb3RMb2FkaW5ncyhtdWx0aWxldmVsUENBLnJlc3VsdCwgY29tcCA9IDIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuZGlzcGxheSA9IDEwLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGl0bGUgPSAiVG9wIDEwIGZlYXR1cmVzIG9uIE11bHRpbGV2ZWwgUEMyLCBjMTggKCspIikpCgpgYGAKCiMjIyMgQmVhdXRpZnkKCmBgYHtyfQptdWx0aWxldmVsUENBX3Njb3JlcyA8LSBtdWx0aWxldmVsUENBLnJlc3VsdCR2YXJpYXRlcyRYICU+JSAjIHJldHJpZXZlIHNjb3JlcwogIGFzLmRhdGEuZnJhbWUoKSAlPiUKICBtdXRhdGUoc2FtcGxlX0lEID0gRGF0YV9mb3JNUENBX25vNjExMnBvc3RSZWQkc2FtcGxlX0lEKQoKIyBqb2luIHdpdGggbWV0YWRhdGEKbXVsdGlsZXZlbFBDQV9wb2ludHMgPC0gbGVmdF9qb2luKG11bHRpbGV2ZWxQQ0Ffc2NvcmVzLCBEYXRhX2Zvck1QQ0Ffbm82MTEycG9zdFJlZFssMToxMV0pIApgYGAKIyMjIyMgU2NvcmVzCmBgYHtyfQojIHZpc3VhbGl6ZSEKKHBsb3RfbXVsdGlsZXZlbFBDQV9tYW51YWwgPC0gbXVsdGlsZXZlbFBDQV9wb2ludHMgJT4lIAogIGdncGxvdChhZXMoeCA9IFBDMSwgeSA9IFBDMiwgCiAgICAgICAgICAgICBmaWxsID0gZmFjdG9yKHByZV9wb3N0X2ludGVydmVudGlvbiwgbGV2ZWxzID0gYygicHJlX1llbGxvdyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicG9zdF9ZZWxsb3ciLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInByZV9SZWQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInBvc3RfUmVkIikpLAogICAgICAgICAgICAgdGV4dCA9IHNhbXBsZV9JRCkpICsKICAgIGdlb21fcG9pbnQoc2hhcGUgPSAyMSwgYWxwaGEgPSAwLjgpICsKICAgIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDAsIGxpbmV0eXBlID0gImRhc2hlZCIsIGFscGhhPTAuNSkgKwogICAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gMCwgbGluZXR5cGUgPSAiZGFzaGVkIiwgYWxwaGE9MC41KSArCiAgICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCJsZW1vbmNoaWZmb24xIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInllbGxvdzIiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicm9zeWJyb3duMiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJkYXJrcmVkIikpICsKICAgIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSAiYmxhY2siKSArICAKICAgIHRoZW1lX21pbmltYWwoKSArCiAgICBsYWJzKHggPSAiUEMxLCAxMiUgdmFyaWF0aW9uIiwKICAgICAgICAgeSA9ICJQQzIsIDklIHZhcmlhdGlvbiIsCiAgICAgICAgIGZpbGwgPSAiVGltZXBvaW50IiwKICAgICAgICAgdGl0bGUgPSAiTXVsdGlsZXZlbCBQcmluY2lwYWwgQ29tcG9uZW50cyBBbmFseXNpcyBTY29yZXMgUGxvdCIsCiAgICAgICAgIHN1YnRpdGxlID0gIkxvZzIgdHJhbnNmb3JtZWQgZGF0YSwgYzE4ICgrKSB3aXRob3V0IG91dGxpZXIgc3ViamVjdHMiKSkKCmdncGxvdGx5KHBsb3RfbXVsdGlsZXZlbFBDQV9tYW51YWwsCiAgICAgICAgIHRvb2x0aXAgPSAidGV4dCIpCmBgYAoKIyMjIyMgQmlwbG90CgpgYGB7cn0KIyByZXRyaWV2ZSBsb2FkaW5ncwptdWx0aWxldmVsUENBX2xvYWRpbmdzIDwtIG11bHRpbGV2ZWxQQ0EucmVzdWx0JGxvYWRpbmdzJFggJT4lCiAgYXMuZGF0YS5mcmFtZSgpICU+JQogIHJvd25hbWVzX3RvX2NvbHVtbigibXpfcnQiKQpgYGAKCmBgYHtyfQptdWx0aWxldmVsUENBX2xvYWRpbmdzICU+JQogIGZpbHRlcihQQzEgJWluJSBsb2FkaW5nc19tdWx0aWxldmVsUEMxJGltcG9ydGFuY2UKICAgICAgICAgfCBQQzIgJWluJSBsb2FkaW5nc19tdWx0aWxldmVsUEMyJGltcG9ydGFuY2UpICU+JQogIGdncGxvdChhZXMoeCA9IFBDMSwgeSA9IFBDMiwgbGFiZWwgPSBtel9ydCkpICsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwLCBsaW5ldHlwZSA9ICJkYXNoZWQiKSArCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gMCwgbGluZXR5cGUgPSAiZGFzaGVkIikgKwogIGdlb21fcG9pbnQoKSArCiAgZ2VvbV9sYWJlbF9yZXBlbChzaXplID0gMi41KSArCiAgc2NhbGVfZmlsbF9icmV3ZXIoKSArCiAgdGhlbWVfbWluaW1hbCgpICsKICBsYWJzKCB4ID0gIlBDMSwgMTIlIHZhcmlhdGlvbiIsCiAgICAgICAgIHkgPSAiUEMyLCA5JSB2YXJpYXRpb24iLAogICAgICAgdGl0bGUgPSAiTG9hZGluZ3MgUGxvdCBmb3IgTXVsdGlsZXZlbCBQQ0EiLAogICAgICAgc3VidGl0bGUgPSAiYzE4ICgrKSBcblN1YmogNjExMiBhdCBwb3N0IFRvbWF0by1Tb3kgdGltZXBvaW50IHJlbW92ZWQiLCkKYGBgCgoKYGBge3J9CiMgZnggdG8gbm9ybWFsaXplIHNjb3JlcyBzbyB0aGF0IHNjb3JlcyBhbmQgbG9hZGluZ3MgYXJlIG9uIHRoZSBzYW1lIHNjYWxlCm5vcm1hbGl6ZSA8LSBmdW5jdGlvbih4KSByZXR1cm4oKHggLSBtaW4oeCkpLyhtYXgoeCkgLSBtaW4oeCkpKQpgYGAKCmBgYHtyfQojIG5vcm1hbGl6ZSBzY29yZXMKbXVsdGlsZXZlbFBDQV9zY29yZXNfbm9ybWFsaXplZCA8LSBtdWx0aWxldmVsUENBX3Njb3JlcyAlPiUKICBtdXRhdGUoUEMxX25vcm0gPSBzY2FsZShub3JtYWxpemUoUEMxKSwgY2VudGVyID0gVFJVRSwgc2NhbGUgPSBGQUxTRSkpICU+JQogIG11dGF0ZShQQzJfbm9ybSA9IHNjYWxlKG5vcm1hbGl6ZShQQzIpLCBjZW50ZXIgPSBUUlVFLCBzY2FsZSA9IEZBTFNFKSkgJT4lCiAgc2VsZWN0KHNhbXBsZV9JRCwgUEMxX25vcm0sIFBDMl9ub3JtLCBldmVyeXRoaW5nKCkpICMgcmVvcmRlciAKYGBgCgpIb3cgZGlkIGl0IGdvPyBQQzFfbm9ybSBhbmQgUEMyX25vcm0gc2hvdWxkIGFsbCBub3cgYmUgYmV0d2VlbiAtMSBhbmQgMQpgYGB7cn0KaGVhZChtdWx0aWxldmVsUENBX3Njb3Jlc19ub3JtYWxpemVkKSAjIGxvb2tzIGdvb2QKYGBgCgoKTm93IHdlIGNhbiBwbG90IHRvZ2V0aGVyIHRoZSBzY29yZXMgYW5kIGxvYWRpbmdzIGluIG9uZSBwbG90LgpgYGB7cn0KIyBqb2luIHdpdGggbWV0YWRhdGEKbXVsdGlsZXZlbFBDQV9wb2ludHNfbm9ybSA8LSBsZWZ0X2pvaW4obXVsdGlsZXZlbFBDQV9zY29yZXNfbm9ybWFsaXplZCwgRGF0YV9mb3JNUENBX25vNjExMnBvc3RSZWRbLDE6MTFdKSAKYGBgCgpgYGB7ciBtdWx0aWxldmVsIGJpcGxvdCBhcnJvd3N9Cm11bHRpbGV2ZWxQQ0FfcG9pbnRzX25vcm0gJT4lCiAgZ2dwbG90KCkgKwogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDAsIGxpbmV0eXBlID0gImRhc2hlZCIpICsKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAwLCBsaW5ldHlwZSA9ICJkYXNoZWQiKSArCiAgZ2VvbV9wb2ludChhZXMoeCA9IFBDMV9ub3JtLCB5ID0gUEMyX25vcm0sIAogICAgICAgICAgICAgICAgIGZpbGwgPSBmYWN0b3IocHJlX3Bvc3RfaW50ZXJ2ZW50aW9uLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxldmVscyA9IGMoInByZV9ZZWxsb3ciLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicG9zdF9ZZWxsb3ciLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicHJlX1JlZCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJwb3N0X1JlZCIpKSksCiAgICAgICAgICAgICBpbmhlcml0LmFlcyA9IEYsCiAgICAgICAgICAgICBzaGFwZSA9IDIxKSArCiAgZ2VvbV9zZWdtZW50KGRhdGEgPSBtdWx0aWxldmVsUENBX2xvYWRpbmdzICU+JQogICAgICAgICAgICAgICAgIGZpbHRlcihQQzEgJWluJSBsb2FkaW5nc19tdWx0aWxldmVsUEMxJGltcG9ydGFuY2UKICAgICAgICAgICAgICAgICAgICAgICAgfCBQQzIgJWluJSBsb2FkaW5nc19tdWx0aWxldmVsUEMyJGltcG9ydGFuY2UpLCAKICAgICAgICAgICAgICAgYWVzKHggPSAwLCB5ID0gMCwgCiAgICAgICAgICAgICAgICAgICB4ZW5kID0gKFBDMSo0KSwgeWVuZCA9IChQQzIqNCkpLCAKICAgICAgICAgICAgICAgYXJyb3cgPSBhcnJvdyhsZW5ndGggPSB1bml0KDEvMiwgInBpY2FzIikpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG9yID0gImJsYWNrIiwgYWxwaGE9MC41NSkgKwogIGdlb21fbGFiZWxfcmVwZWwoZGF0YSA9IG11bHRpbGV2ZWxQQ0FfbG9hZGluZ3MgJT4lCiAgICAgICAgICAgICAgICAgICAgZmlsdGVyKFBDMSAlaW4lIGxvYWRpbmdzX211bHRpbGV2ZWxQQzEkaW1wb3J0YW5jZQogICAgICAgICAgICAgICAgICAgICAgICB8IFBDMiAlaW4lIGxvYWRpbmdzX211bHRpbGV2ZWxQQzIkaW1wb3J0YW5jZSksCiAgICAgICAgICAgICAgICAgICBhZXMoeCA9IFBDMSo0LjYsIHkgPSBQQzIqNSwgbGFiZWwgPSBtel9ydCksIAogICAgICAgICAgICAgICAgICAgc2l6ZSA9IDIuNSwgc2VnbWVudC5jb2xvciA9ICJ0cmFuc3BhcmVudCIsCiAgICAgICAgICAgICAgICAgICBkaXJlY3Rpb24gPSAiYm90aCIsIG1heC5vdmVybGFwcyA9IDE1KSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygibGVtb25jaGlmZm9uMSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJ5ZWxsb3cyIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInJvc3licm93bjIiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiZGFya3JlZCIpKSArCiAgdGhlbWVfbWluaW1hbCgpICsKICBsYWJzKHggPSAiUEMxLCAxMiUgdmFyaWF0aW9uIiwKICAgICAgICAgeSA9ICJQQzIsIDklIHZhcmlhdGlvbiIsCiAgICAgICB0aXRsZSA9ICJCaXBsb3QgZm9yIE11bHRpbGV2ZWwgUENBIiwKICAgICAgIHN1YnRpdGxlID0gImMxOCAoKykgXG5TdWJqIDYxMTIgYXQgcG9zdCBUb21hdG8tU295IHRpbWVwb2ludCByZW1vdmVkIiwKICAgICAgIGZpbGwgPSAiVGltZXBvaW50IiwKICAgICAgIGNhcHRpb24gPSAiIikKYGBgCgoKYGBge3IgbXVsdGlsZXZlbCBiaXBsb3Qgbm8gYXJyb3dzfQptdWx0aWxldmVsUENBX3BvaW50c19ub3JtICU+JQogIGdncGxvdCgpICsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwLCBsaW5ldHlwZSA9ICJkYXNoZWQiKSArCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gMCwgbGluZXR5cGUgPSAiZGFzaGVkIikgKwogIGdlb21fcG9pbnQoYWVzKHggPSBQQzFfbm9ybSwgeSA9IFBDMl9ub3JtLCAKICAgICAgICAgICAgICAgICBmaWxsID0gZmFjdG9yKHByZV9wb3N0X2ludGVydmVudGlvbiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsZXZlbHMgPSBjKCJwcmVfWWVsbG93IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInBvc3RfWWVsbG93IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInByZV9SZWQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicG9zdF9SZWQiKSkpLAogICAgICAgICAgICAgaW5oZXJpdC5hZXMgPSBGLAogICAgICAgICAgICAgc2hhcGUgPSAyMSkgKwogIGdlb21fbGFiZWxfcmVwZWwoZGF0YSA9IG11bHRpbGV2ZWxQQ0FfbG9hZGluZ3MgJT4lCiAgICAgICAgICAgICAgICAgICAgZmlsdGVyKFBDMSAlaW4lIGxvYWRpbmdzX211bHRpbGV2ZWxQQzEkaW1wb3J0YW5jZQogICAgICAgICAgICAgICAgICAgICAgICB8IFBDMiAlaW4lIGxvYWRpbmdzX211bHRpbGV2ZWxQQzIkaW1wb3J0YW5jZSksCiAgICAgICAgICAgICAgICAgICBhZXMoeCA9IFBDMSo0LjYsIHkgPSBQQzIqNSwgbGFiZWwgPSBtel9ydCksIAogICAgICAgICAgICAgICAgICAgc2l6ZSA9IDIuNSwgc2VnbWVudC5jb2xvciA9ICJ0cmFuc3BhcmVudCIsCiAgICAgICAgICAgICAgICAgICBkaXJlY3Rpb24gPSAiYm90aCIsIG1heC5vdmVybGFwcyA9IDE1KSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygibGVtb25jaGlmZm9uMSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJ5ZWxsb3cyIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInJvc3licm93bjIiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiZGFya3JlZCIpLAogICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGMoInByZSBjb250cm9sIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJwb3N0IGNvbnRyb2wiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInByZSB0b21hdG8tc295IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJwb3N0IHRvbWF0by1zb3kiKSkgKwogIHRoZW1lX21pbmltYWwoKSArCiAgbGFicyh4ID0gIlBDMSwgMTIlIHZhcmlhdGlvbiIsCiAgICAgICAgIHkgPSAiUEMyLCA5JSB2YXJpYXRpb24iLAogICAgICAgdGl0bGUgPSAiQmlwbG90IGZvciBNdWx0aWxldmVsIFBDQSIsCiAgICAgICBzdWJ0aXRsZSA9ICJjMTggKCspIFxuU3ViaiA2MTEyIGF0IHBvc3QgVG9tYXRvLVNveSB0aW1lcG9pbnQgcmVtb3ZlZCIsCiAgICAgICBjYXB0aW9uID0gIiIsCiAgICAgICBmaWxsID0gIlRpbWVwb2ludCIpCmBgYAoKIyMjIHByZV9wb3N0CmBgYHtyfQptdWx0aWxldmVsUENBLnJlc3VsdCA8LSBtaXhPbWljczo6cGNhKERhdGFfZm9yTVBDQVssLShjKDE6MTEpKV0sIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgbXVsdGlsZXZlbCA9IERhdGFfZm9yTVBDQSRTdWJqZWN0LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgc2NhbGUgPSBGQUxTRSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNlbnRlciA9IEZBTFNFKQoKcGxvdEluZGl2KG11bHRpbGV2ZWxQQ0EucmVzdWx0LCAKICAgICAgICAgIGluZC5uYW1lcyA9IERhdGFfZm9yTVBDQSRTdWJqZWN0LCAKICAgICAgICAgIGdyb3VwID0gRGF0YV9mb3JNUENBJHByZV9wb3N0LCAKICAgICAgICAgIGxlZ2VuZCA9IFRSVUUsIAogICAgICAgICAgbGVnZW5kLnRpdGxlID0gIlRyZWF0bWVudCIsIAogICAgICAgICAgdGl0bGUgPSAnTXVsdGlsZXZlbCBQQ0EsIGMxOCAoKyksIExvZzIgdHJhbnNmb3JtZWQnKQoKYGBgCgojIyMjIExvYWRpbmdzIAoKYGBge3J9CnBsb3RMb2FkaW5ncyhtdWx0aWxldmVsUENBLnJlc3VsdCwgbmRpc3BsYXkgPSAxNSwgY29tcCA9IDIpCmBgYAoKCiMgVW5pdmFyaWF0ZSBhbmFseXNpcwoKIyMgV3JhbmdsZSBkYXRhCgp1c2UgdGlkeSBkYXRhCmBgYHtyfQojIHVzZSB0aWR5IGRhdGEgCmhlYWQoYW5ub19pbXBfbWV0YWJpbmRfY2x1c3RfdGlkeV9sb2cyKQpgYGAKCmBgYHtyfQojIHJlbW92ZSBRQ3MKZGZfZm9yX3N0YXRzIDwtIGFubm9faW1wX21ldGFiaW5kX2NsdXN0X3RpZHlfbG9nMiAlPiUKICBmaWx0ZXIoSW50ZXJ2ZW50aW9uICE9ICJRQyIpCgojIGNoZWNrIGlmIFFDcyB3ZXJlIHJlbW92ZWQKdW5pcXVlKGRmX2Zvcl9zdGF0cyRJbnRlcnZlbnRpb24pCmBgYAoKCmBgYHtyfQojIGRmIHdpdGhvdXQgb3V0bGllcnMKZGZfZm9yX3N0YXRzX25vT3V0bGllciA8LSBkZl9mb3Jfc3RhdHMgJT4lCiAgZmlsdGVyKFN1YmplY3QgIT0gIjYxMDYiLAogICAgICAgICBTdWJqZWN0ICE9ICI2MTEyIikKCiMgY2hlY2sgaWYgb3V0bGllciB3YXMgcmVtb3ZlZAp1bmlxdWUoZGZfZm9yX3N0YXRzX25vT3V0bGllciRTdWJqZWN0KQpgYGAKCgpgYGB7cn0KIyB0dXJuIG9mZiBzY2kgbm90YXRpb24gb3V0cHV0cwpvcHRpb25zKHNjaXBlbiA9IDk5OSkKYGBgCgoKIyMgUGFyYW1ldHJpYyB0ZXN0cwoKIyMjIEFOT1ZBIChyZXBlYXRlZCBtZWFzdXJlcykgYWNyb3NzIHRpbWVwb2ludHMKCmBgYHtyfQoKYW5vdmFfb3V0cG91dF9kZiA8LSBkZl9mb3Jfc3RhdHNfbm9PdXRsaWVyICU+JQogIGRwbHlyOjpzZWxlY3QoU3ViamVjdCwgcHJlX3Bvc3RfaW50ZXJ2ZW50aW9uLCBGZWF0dXJlX0lELCByZWxfYWJ1bmRfbG9nMikgJT4lCiAgZ3JvdXBfYnkoRmVhdHVyZV9JRCkgJT4lCiAgYW5vdmFfdGVzdChyZWxfYWJ1bmRfbG9nMiB+IHByZV9wb3N0X2ludGVydmVudGlvbiwgd2lkID0gU3ViamVjdCwKICAgICAgICAgICAgIGRldGFpbGVkID0gVFJVRSkgJT4lCiAgYWRqdXN0X3B2YWx1ZShtZXRob2QgPSAiQkgiKSAlPiUKICBhcy5kYXRhLmZyYW1lKCkKCmFub3ZhX3NpZyA8LSBhbm92YV9vdXRwb3V0X2RmICU+JQogIGZpbHRlcihwLmFkaiA8PSAwLjA1KQoKIyBob3cgbWFueSBzaWduaWZpY2FudCBmZWF0dXJlcz8KbnJvdyhhbm92YV9zaWcpCiAgCmBgYAoKCmBgYHtyfQojIHR1a2V5J3MgcG9zdGhvYwp0dWtleV9hbm92YSA8LSBkZl9mb3Jfc3RhdHNfbm9PdXRsaWVyICU+JSAKICBkcGx5cjo6c2VsZWN0KFN1YmplY3QsIHByZV9wb3N0X2ludGVydmVudGlvbiwgRmVhdHVyZV9JRCwgcmVsX2FidW5kX2xvZzIpICU+JQogIGdyb3VwX2J5KEZlYXR1cmVfSUQpICU+JQogIHR1a2V5X2hzZChyZWxfYWJ1bmRfbG9nMiB+IHByZV9wb3N0X2ludGVydmVudGlvbiwgd2lkID0gc3ViamVjdCkKYGBgCgojIyMjIGJveHBsb3RzCmBgYHtyLCBmaWcuaGVpZ2h0PTEwLCBmaWcud2lkdGg9MTV9CmRmX2Zvcl9zdGF0c19ub091dGxpZXIgJT4lIAogIGZpbHRlcihGZWF0dXJlX0lEICVpbiUgYW5vdmFfc2lnJEZlYXR1cmVfSUQpICU+JQogIGdncGxvdChhZXMoeCA9IGZhY3RvcihwcmVfcG9zdF9pbnRlcnZlbnRpb24sCiAgICAgICAgICAgICAgICAgICAgICAgIGxldmVscyA9IGMoInByZV9ZZWxsb3ciLCAicG9zdF9ZZWxsb3ciLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicHJlX1JlZCIsICJwb3N0X1JlZCIpKSwgCiAgICAgICAgICAgICB5ID0gcmVsX2FidW5kX2xvZzIsIGZpbGwgPSBJbnRlcnZlbnRpb24pKSArCiAgZ2VvbV9ib3hwbG90KG91dGxpZXIuc2hhcGUgPSBOQSkgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoIlllbGxvdyIgPSAiZ29sZCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiUmVkIiA9ICJ0b21hdG8xIikpICsKICBnZW9tX2xpbmUoYWVzKGdyb3VwID0gU3ViamVjdCksIGxpbmV3aWR0aCA9IDAuMikgKwogIGZhY2V0X3dyYXAodmFycyhGZWF0dXJlX0lEKSwgc2NhbGVzID0gImZyZWVfeSIpICsgCiAgdGhlbWVfY2xlYW4oKQpgYGAKCgojIyMjIEhlYXRtYXAgb2YgZmVhdHVyZXMgc2lnbmlmaWNhbnQgYnkgQU5PVkEKYGBge3IsIGZpZy53aWR0aD04LCBmaWcuYXNwPTF9CkFOT1ZBX2hlYXRtYXBfZGF0YSA8LSBhbm5vX2ltcF9tZXRhYmluZF9jbHVzdF9sb2cyX25vUUNzICU+JQogIHVuaXRlKCJTdWJqZWN0X3ByZV9wb3N0X2ludGVydmVudGlvbiIsIFN1YmplY3QsIHByZV9wb3N0X2ludGVydmVudGlvbiwgc2VwID0gIl8iLCByZW1vdmUgPSBGQUxTRSkgJT4lCiAgZHBseXI6OnNlbGVjdChzYW1wbGVfSUQsIFN1YmplY3QsIFN1YmplY3RfcHJlX3Bvc3RfaW50ZXJ2ZW50aW9uLCBwcmVfcG9zdF9pbnRlcnZlbnRpb24sIGFsbF9vZihhbm92YV9zaWckRmVhdHVyZV9JRCkpICU+JQogIGNvbHVtbl90b19yb3duYW1lcygic2FtcGxlX0lEIikKCkFOT1ZBX2hlYXRtYXAgPC0gCiAgcGhlYXRtYXAodChBTk9WQV9oZWF0bWFwX2RhdGFbLC1jKDE6MyldKSwKICAgICAgICAgICBzY2FsZSA9ICJyb3ciLAogICAgICAgICAgIGNsdXN0ZXJfcm93cyA9IFRSVUUsCiAgICAgICAgICAgY2x1c3RlcmluZ19kaXN0YW5jZV9yb3dzID0gImV1Y2xpZGVhbiIsCiAgICAgICAgICAgY2x1c3RlcmluZ19kaXN0YW5jZV9jb2xzID0gImV1Y2xpZGVhbiIsCiAgICAgICAgICAgY2x1c3RlcmluZ19tZXRob2QgPSAid2FyZC5EMiIsCiAgICAgICAgICAgbGFiZWxzX2NvbCA9IEFOT1ZBX2hlYXRtYXBfZGF0YSRTdWJqZWN0X3ByZV9wb3N0X2ludGVydmVudGlvbiwKICAgICAgICAgICBjb2xvciA9IGNvbG9yUmFtcFBhbGV0dGUoYygiIzY3YTljZiIsICIjZjdmN2Y3IiwgIiNlZjhhNjIiKSkoMTYpLAogICAgICAgICAgIG1haW4gPSAiSGVhdG1hcCBvZiBmZWF0dXJlcyBzaWduaWZpY2FudCBhY3Jvc3MgdGltZXBvaW50cyBcbmJ5IHJlcGVhdGVkIG1lYXN1cmVzIG9uZS13YXkgQU5PVkEgXG5CZW5qYW1vbmktSG9jaGJlcmcgY29ycmVjdGVkIHAtdmFsdWVzID4gMC4wNSBcbmMxOCAoKykiKQogIApgYGAKCgoKCmBgYHtyfQpBTk9WQV9oZWF0bWFwX2RhdGEyIDwtIGFubm9faW1wX21ldGFiaW5kX2NsdXN0X2xvZzJfbm9RQ3MgJT4lCiAgZmlsdGVyKFN1YmplY3QgIT0gNjEwNiwKICAgICAgICAgU3ViamVjdCAhPSA2MTEyKSAlPiUKICB1bml0ZSgiU3ViamVjdF9wcmVfcG9zdF9pbnRlcnZlbnRpb24iLCBTdWJqZWN0LCBwcmVfcG9zdF9pbnRlcnZlbnRpb24sIHNlcCA9ICJfIiwgcmVtb3ZlID0gRkFMU0UpICU+JQogIGRwbHlyOjpzZWxlY3Qoc2FtcGxlX0lELCBTdWJqZWN0X3ByZV9wb3N0X2ludGVydmVudGlvbiwgcHJlX3Bvc3RfaW50ZXJ2ZW50aW9uLCBhbGxfb2YoYW5vdmFfc2lnJEZlYXR1cmVfSUQpKSAlPiUKICBjb2x1bW5fdG9fcm93bmFtZXMoInNhbXBsZV9JRCIpIApgYGAKCgpgYGB7cn0KIyBpIG5lZWQgd2lkZSBkZgpkZl9mb3Jfc3RhdHNfbm9PdXRsaWVyX3dpZGUgPC0gZGZfZm9yX3N0YXRzX25vT3V0bGllciAlPiUKICBzZWxlY3QoMToxMSwgRmVhdHVyZV9JRCwgcmVsX2FidW5kX2xvZzIpICU+JQogIHBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSAiRmVhdHVyZV9JRCIsCiAgICAgICAgICAgICAgdmFsdWVzX2Zyb20gPSAicmVsX2FidW5kX2xvZzIiKQoKIyBjaGFuZ2UgcHJlX3Bvc3RfaW50ZXJ2ZW50aW9uIHRvIGZhY3RvcgpkZl9mb3Jfc3RhdHNfbm9PdXRsaWVyX3dpZGUkcHJlX3Bvc3RfaW50ZXJ2ZW50aW9uIDwtIGFzLmZhY3RvcihkZl9mb3Jfc3RhdHNfbm9PdXRsaWVyX3dpZGUkcHJlX3Bvc3RfaW50ZXJ2ZW50aW9uKQoKIyBjcmVhdGUgYW5ub3RhdGlvbiByb3dzIGZvciB0cmVhdG1lbnQgYW5kIHdyYW5nbGUKIyBzZWxlY3Qgc2FtcGxlIGNvbCBmcm9tIGhlYXRtYXAgbWV0YWRhdGEgKGFsc28gZW5zdXJlcyB0aGUgb3JkZXIgaXMgY29ycmVjdCkKYW5ub190cnRfcm93IDwtIGFzLmRhdGEuZnJhbWUocm93bmFtZXMoQU5PVkFfaGVhdG1hcF9kYXRhMikpCgojIHB1bGwgZGVzaXJlZCBjb2x1bW5zCmFubm9fdHJ0X3JvdyRwcmVfcG9zdF9pbnRlcnZlbnRpb24gPC0gQU5PVkFfaGVhdG1hcF9kYXRhMiRwcmVfcG9zdF9pbnRlcnZlbnRpb24KCiMgc2VsZWN0IHRydAphbm5vX3RydF9yb3cgPC0gYW5ub190cnRfcm93ICU+JQogIGRwbHlyOjpzZWxlY3QocHJlX3Bvc3RfaW50ZXJ2ZW50aW9uKSAKCiMgZ2V0IHJvd25hbWVzIHRvIG1hdGNoIGhlYXRtYXAKcm93bmFtZXMoYW5ub190cnRfcm93KSA8LSByb3duYW1lcyhBTk9WQV9oZWF0bWFwX2RhdGEyKQoKIyBjcmVhdGUgYW5ub3RhdGlvbiBjb2xvcnMKYW5ub3RhdGlvbl9jb2xvcnMgPC0gbGlzdChwcmVfcG9zdF9pbnRlcnZlbnRpb24gPSBjKCJwcmVfWWVsbG93IiA9ICJsZW1vbmNoaWZmb24xIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJwb3N0X1llbGxvdyIgPSAieWVsbG93MiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicHJlX1JlZCIgPSAicm9zeWJyb3duMiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicG9zdF9SZWQiID0gImRhcmtyZWQiKSkKYGBgCgpgYGB7ciwgZmlnLmhlaWdodD04fQooQU5PVkFfaGVhdG1hcCA8LSAKICBwaGVhdG1hcCh0KEFOT1ZBX2hlYXRtYXBfZGF0YTJbLC1jKDE6MildKSwKICAgICAgICAgICBzY2FsZSA9ICJyb3ciLAogICAgICAgICAgIGNsdXN0ZXJfcm93cyA9IFRSVUUsCiAgICAgICAgICAgY2x1c3RlcmluZ19kaXN0YW5jZV9yb3dzID0gImV1Y2xpZGVhbiIsCiAgICAgICAgICAgY2x1c3RlcmluZ19kaXN0YW5jZV9jb2xzID0gImV1Y2xpZGVhbiIsCiAgICAgICAgICAgY2x1c3RlcmluZ19tZXRob2QgPSAid2FyZC5EMiIsCiAgICAgICAgICAgbGFiZWxzX2NvbCA9IEFOT1ZBX2hlYXRtYXBfZGF0YTIkU3ViamVjdF9wcmVfcG9zdF9pbnRlcnZlbnRpb24sCiAgICAgICAgICAgY29sb3IgPSBjb2xvclJhbXBQYWxldHRlKGMoIiM2N2E5Y2YiLCAiI2Y3ZjdmNyIsICIjZWY4YTYyIikpKDE2KSwKICAgICAgICAgICBhbm5vdGF0aW9uX2NvbCA9IGFubm9fdHJ0X3JvdywKICAgICAgICAgICBhbm5vdGF0aW9uX2NvbG9ycyA9IGFubm90YXRpb25fY29sb3JzLAogICAgICAgICAgIGFubm90YXRpb25fbmFtZXNfY29sID0gRiwKICAgICAgICAgICBtYWluID0gIkhlYXRtYXAgb2YgZmVhdHVyZXMgc2lnbmlmaWNhbnQgYWNyb3NzIHRpbWVwb2ludHMgXG5ieSByZXBlYXRlZCBtZWFzdXJlcyBvbmUtd2F5IEFOT1ZBIFxuQmVuamFtb25pLUhvY2hiZXJnIGNvcnJlY3RlZCBwLXZhbHVlcyA+IDAuMDUgXG5SUExDLU1TICgrKSIpKQogIApgYGAKCgpgYGB7cn0KZ2dzYXZlKHBsb3QgPSBBTk9WQV9oZWF0bWFwLCBoZWlnaHQgPSA4LCB3aWR0aCA9IDEyLAogICAgICAgZmlsZW5hbWUgPSAicGxvdHMgYW5kIGZpZ3VyZXMvUlBMQ01TUE9TX2hlYXRtYXBfQU5PVkFzaWcuc3ZnIikKYGBgCgoKIyMjIFBhaXJlZCB0IHRlc3RzCgpIZXJlLCBJIGFtIGNvbXBhcmluZyBwcmUtIHRvIHBvc3QtaW50ZXJ2ZW50aW9uIGZvciBib3RoIHllbGxvdyBhbmQgdG9tYXRvIHNveSAoUmVkKSBqdWljZSBpbnRlcnZlbnRpb25zLiBJIGFsc28gY29tcGFyZSBwb3N0LXllbGxvdyB0byBwb3N0LXJlZCBpbnRlcnZlbnRpb24uIEkgYW0gdXNpbmcgdGhlIGxvZyB0cmFuc2Zvcm1lZCB2YWx1ZXMgb2YgcmVsIGFidW5kYW5jZSBzaW5jZSBwYXJhbWV0cmljIHRlc3RzIGFzc3VtZSBub3JtYWxpdHkuCgojIyMjIEN0cmwKYGBge3J9CiMgcnVuIHBhaXJlZCB0LXRlc3RzIGZvciBjb250cm9sIGludGVydmVudGlvbgpjdHJsX3QudGVzdF9wYWlyZWQgPC0gZGZfZm9yX3N0YXRzICU+JQogIGZpbHRlcihJbnRlcnZlbnRpb24gPT0gIlllbGxvdyIpICU+JQogIGRwbHlyOjpzZWxlY3QoU3ViamVjdCwgcHJlX3Bvc3QsIG16X3J0LCByZWxfYWJ1bmRfbG9nMikgJT4lCiAgZ3JvdXBfYnkobXpfcnQpICU+JQogIHRfdGVzdChyZWxfYWJ1bmRfbG9nMiB+IHByZV9wb3N0LCAKICAgICAgICAgcGFpcmVkID0gVFJVRSwgCiAgICAgICAgIHAuYWRqdXN0Lm1ldGhvZCA9ICJCSCIpICU+JSAjIEJlbmphbWluaS1Ib2NoYmVyZyBjb250cm9sbGluZyB0byBsb3dlciBmYWxzZSBwb3NpdGl2ZXMKICBhZGRfc2lnbmlmaWNhbmNlKCkKYGBgCgpTdGF0aXN0aWNhbGx5IHNpZ25pZmljYW50IGZlYXR1cmVzCmBgYHtyfQojIHdoaWNoIGZlYXR1cmVzIGFyZSBzaWduaWZpY2FudD8KY3RybF90LnRlc3RfcGFpcmVkX3NpZyA8LSBjdHJsX3QudGVzdF9wYWlyZWQgJT4lCiAgZmlsdGVyKHAgPD0gMC4wNSkKdGliYmxlKGN0cmxfdC50ZXN0X3BhaXJlZF9zaWcpCgojIGhvdyBtYW55IGFyZSBzaWduaWZpY2FudD8KbnJvdyhjdHJsX3QudGVzdF9wYWlyZWRfc2lnKQpgYGAKCgoKIyMjIyBDdHJsIG5vIG91dGxpZXIKYGBge3J9CiMgcnVuIHBhaXJlZCB0LXRlc3RzIGZvciBjb250cm9sIGludGVydmVudGlvbgpjdHJsX25vT3V0bGllcl90LnRlc3RfcGFpcmVkIDwtIGRmX2Zvcl9zdGF0c19ub091dGxpZXIgJT4lCiAgZmlsdGVyKEludGVydmVudGlvbiA9PSAiWWVsbG93IikgJT4lCiAgZHBseXI6OnNlbGVjdChTdWJqZWN0LCBwcmVfcG9zdCwgbXpfcnQsIHJlbF9hYnVuZF9sb2cyKSAlPiUKICBncm91cF9ieShtel9ydCkgJT4lCiAgdF90ZXN0KHJlbF9hYnVuZF9sb2cyIH4gcHJlX3Bvc3QsIAogICAgICAgICBwYWlyZWQgPSBUUlVFLCAKICAgICAgICAgcC5hZGp1c3QubWV0aG9kID0gIkJIIikgJT4lICMgQmVuamFtaW5pLUhvY2hiZXJnIGNvbnRyb2xsaW5nIHRvIGxvd2VyIGZhbHNlIHBvc2l0aXZlcwogIGFkZF9zaWduaWZpY2FuY2UoKQpgYGAKClN0YXRpc3RpY2FsbHkgc2lnbmlmaWNhbnQgZmVhdHVyZXMKYGBge3J9CiMgd2hpY2ggZmVhdHVyZXMgYXJlIHNpZ25pZmljYW50PwpjdHJsX25vT3V0bGllcl90LnRlc3RfcGFpcmVkX3NpZyA8LSBjdHJsX25vT3V0bGllcl90LnRlc3RfcGFpcmVkICU+JQogIGZpbHRlcihwIDw9IDAuMDUpCnRpYmJsZShjdHJsX25vT3V0bGllcl90LnRlc3RfcGFpcmVkX3NpZykKCiMgaG93IG1hbnkgYXJlIHNpZ25pZmljYW50Pwpucm93KGN0cmxfbm9PdXRsaWVyX3QudGVzdF9wYWlyZWRfc2lnKQpgYGAKCgojIyMjIFJlZApgYGB7cn0KIyBydW4gcGFpcmVkIHQtdGVzdHMgZm9yIGNvbnRyb2wgaW50ZXJ2ZW50aW9uCnJlZF90LnRlc3RfcGFpcmVkIDwtIGRmX2Zvcl9zdGF0cyAlPiUKICBmaWx0ZXIoSW50ZXJ2ZW50aW9uID09ICJSZWQiKSAlPiUKICBkcGx5cjo6c2VsZWN0KFN1YmplY3QsIHByZV9wb3N0LCBtel9ydCwgcmVsX2FidW5kX2xvZzIpICU+JQogIGdyb3VwX2J5KG16X3J0KSAlPiUKICB0X3Rlc3QocmVsX2FidW5kX2xvZzIgfiBwcmVfcG9zdCwgCiAgICAgICAgIHBhaXJlZCA9IFRSVUUsIAogICAgICAgICBwLmFkanVzdC5tZXRob2QgPSAiQkgiKSAlPiUgIyBCZW5qYW1pbmktSG9jaGJlcmcgY29udHJvbGxpbmcgdG8gbG93ZXIgZmFsc2UgcG9zaXRpdmVzCiAgYWRkX3NpZ25pZmljYW5jZSgpCmBgYAoKU3RhdGlzdGljYWxseSBzaWduaWZpY2FudCBmZWF0dXJlcwpgYGB7cn0KIyB3aGljaCBmZWF0dXJlcyBhcmUgc2lnbmlmaWNhbnQ/CnJlZF90LnRlc3RfcGFpcmVkX3NpZyA8LSByZWRfdC50ZXN0X3BhaXJlZCAlPiUKICBmaWx0ZXIocCA8PSAwLjA1KQp0aWJibGUocmVkX3QudGVzdF9wYWlyZWRfc2lnKQoKIyBob3cgbWFueSBhcmUgc2lnbmlmaWNhbnQ/Cm5yb3cocmVkX3QudGVzdF9wYWlyZWRfc2lnKQpgYGAKCgojIyMjIFJlZCBubyBvdXRsaWVyCmBgYHtyfQojIHJ1biBwYWlyZWQgdC10ZXN0cyBmb3IgY29udHJvbCBpbnRlcnZlbnRpb24KcmVkX25vT3V0bGllcl90LnRlc3RfcGFpcmVkIDwtIGRmX2Zvcl9zdGF0c19ub091dGxpZXIgJT4lCiAgZmlsdGVyKEludGVydmVudGlvbiA9PSAiUmVkIikgJT4lCiAgZHBseXI6OnNlbGVjdChTdWJqZWN0LCBwcmVfcG9zdCwgbXpfcnQsIHJlbF9hYnVuZF9sb2cyKSAlPiUKICBncm91cF9ieShtel9ydCkgJT4lCiAgdF90ZXN0KHJlbF9hYnVuZF9sb2cyIH4gcHJlX3Bvc3QsIAogICAgICAgICBwYWlyZWQgPSBUUlVFLCAKICAgICAgICAgcC5hZGp1c3QubWV0aG9kID0gIkJIIikgJT4lICMgQmVuamFtaW5pLUhvY2hiZXJnIGNvbnRyb2xsaW5nIHRvIGxvd2VyIGZhbHNlIHBvc2l0aXZlcwogIGFkZF9zaWduaWZpY2FuY2UoKQpgYGAKClN0YXRpc3RpY2FsbHkgc2lnbmlmaWNhbnQgZmVhdHVyZXMKYGBge3J9CiMgd2hpY2ggZmVhdHVyZXMgYXJlIHNpZ25pZmljYW50PwpyZWRfbm9PdXRsaWVyX3QudGVzdF9wYWlyZWRfc2lnIDwtIHJlZF9ub091dGxpZXJfdC50ZXN0X3BhaXJlZCAlPiUKICBmaWx0ZXIocCA8PSAwLjA1KQp0aWJibGUocmVkX25vT3V0bGllcl90LnRlc3RfcGFpcmVkX3NpZykKCiMgaG93IG1hbnkgYXJlIHNpZ25pZmljYW50Pwpucm93KHJlZF9ub091dGxpZXJfdC50ZXN0X3BhaXJlZF9zaWcpCmBgYAoKCgojIyMjIFBvc3QtcmVkIHZzIHBvc3QteWVsbG93CgpgYGB7cn0KIyBydW4gcGFpcmVkIHQtdGVzdHMgZm9yIHBvc3QgaW50ZXJ2ZW50aW9ucwpwb3N0X3QudGVzdF9wYWlyZWQgPC0gZGZfZm9yX3N0YXRzICU+JQogIGZpbHRlcihwcmVfcG9zdCA9PSAicG9zdCIpICU+JQogIGRwbHlyOjpzZWxlY3QoU3ViamVjdCwgSW50ZXJ2ZW50aW9uLCBtel9ydCwgcmVsX2FidW5kX2xvZzIpICU+JQogIGdyb3VwX2J5KG16X3J0KSAlPiUKICB0X3Rlc3QocmVsX2FidW5kX2xvZzIgfiBJbnRlcnZlbnRpb24sIAogICAgICAgICBwYWlyZWQgPSBUUlVFLCAKICAgICAgICAgcC5hZGp1c3QubWV0aG9kID0gIkJIIikgJT4lICMgQmVuamFtaW5pLUhvY2hiZXJnIGNvbnRyb2xsaW5nIHRvIGxvd2VyIGZhbHNlIHBvc2l0aXZlcwogIGFkZF9zaWduaWZpY2FuY2UoKQpgYGAKClN0YXRpc3RpY2FsbHkgc2lnbmlmaWNhbnQgZmVhdHVyZXMKYGBge3J9CiMgd2hpY2ggZmVhdHVyZXMgYXJlIHNpZ25pZmljYW50Pwpwb3N0X3QudGVzdF9wYWlyZWRfc2lnIDwtIHBvc3RfdC50ZXN0X3BhaXJlZCAlPiUKICBmaWx0ZXIocCA8PSAwLjA1KQp0aWJibGUocG9zdF90LnRlc3RfcGFpcmVkX3NpZykKCiMgaG93IG1hbnkgYXJlIHNpZ25pZmljYW50Pwpucm93KHBvc3RfdC50ZXN0X3BhaXJlZF9zaWcpCmBgYAoKIyMjIyBQb3N0LXJlZCB2cyBwb3N0LXllbGxvdyBubyBPdXRsaWVyCgpgYGB7cn0KIyBydW4gcGFpcmVkIHQtdGVzdHMgZm9yIHBvc3QgaW50ZXJ2ZW50aW9ucwpwb3N0X25vT3V0bGllcl90LnRlc3RfcGFpcmVkIDwtIGRmX2Zvcl9zdGF0cyAlPiUKICBmaWx0ZXIocHJlX3Bvc3QgPT0gInBvc3QiLAogICAgICAgICBTdWJqZWN0ICE9ICI2MTA2IikgJT4lCiAgZHBseXI6OnNlbGVjdChTdWJqZWN0LCBJbnRlcnZlbnRpb24sIG16X3J0LCByZWxfYWJ1bmRfbG9nMikgJT4lCiAgZ3JvdXBfYnkobXpfcnQpICU+JQogIHRfdGVzdChyZWxfYWJ1bmRfbG9nMiB+IEludGVydmVudGlvbiwgCiAgICAgICAgIHBhaXJlZCA9IFRSVUUsIAogICAgICAgICBwLmFkanVzdC5tZXRob2QgPSAiQkgiKSAlPiUgIyBCZW5qYW1pbmktSG9jaGJlcmcgY29udHJvbGxpbmcgdG8gbG93ZXIgZmFsc2UgcG9zaXRpdmVzCiAgYWRkX3NpZ25pZmljYW5jZSgpCmBgYAoKU3RhdGlzdGljYWxseSBzaWduaWZpY2FudCBmZWF0dXJlcwpgYGB7cn0KIyB3aGljaCBmZWF0dXJlcyBhcmUgc2lnbmlmaWNhbnQ/CnBvc3Rfbm9PdXRsaWVyX3QudGVzdF9wYWlyZWRfc2lnIDwtIHBvc3Rfbm9PdXRsaWVyX3QudGVzdF9wYWlyZWQgJT4lCiAgZmlsdGVyKHAgPD0gMC4wNSkKdGliYmxlKHBvc3Rfbm9PdXRsaWVyX3QudGVzdF9wYWlyZWRfc2lnKQoKIyBob3cgbWFueSBhcmUgc2lnbmlmaWNhbnQ/Cm5yb3cocG9zdF9ub091dGxpZXJfdC50ZXN0X3BhaXJlZF9zaWcpCmBgYAoKCgojIyMgVm9sY2FubyBwbG90cwoKIyMjIyBQb3N0LWludGVydmVudGlvbiBjb21wYXJpc29ucyAKCiMjIyMjIFdyYW5nbGUgKG5vIG91dGxpZXIpCmBgYHtyfQojIGNhbGN1bGF0ZSBtZWFuIHJlbCBhYnVuZCAobm90IGxvZykgYnkgc2FtcGxlLCBhbmQgYXZnIGZvbGQgY2hhbmdlIChGQykgZGlmZiBieSBmZWF0dXJlCnJlZF92X3llbF92b2xjYW5vX2RhdGFfbm9PdXRsaWVyIDwtIGRmX2Zvcl9zdGF0cyAlPiUKICBmaWx0ZXIocHJlX3Bvc3QgPT0gInBvc3QiLAogICAgICAgICBTdWJqZWN0ICE9IDYxMDYsCiAgICAgICAgIFN1YmplY3QgIT0gNjExMikgJT4lICMgcmVtb3ZlIG91dGxpZXIgc3ViagogIGdyb3VwX2J5KEludGVydmVudGlvbiwgbXpfcnQpICU+JQogIHN1bW1hcml6ZShtZWFuX3JlbF9hYnVuZCA9IG1lYW4oMl5yZWxfYWJ1bmRfbG9nMikpICU+JQogIHBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSBJbnRlcnZlbnRpb24sIHZhbHVlc19mcm9tID0gbWVhbl9yZWxfYWJ1bmQpICU+JQogIG11dGF0ZShGQ19wb3N0UmVkX2Rpdl9wb3N0WWVsbG93ID0gUmVkL1llbGxvdykgCgojIGJpbmQgYmFjayBwdmFsCnJlZF92X3llbF90b2JpbmRfbm9PdXRsaWVyIDwtIHBvc3Rfbm9PdXRsaWVyX3QudGVzdF9wYWlyZWQgJT4lCiAgZHBseXI6OnNlbGVjdChwKQoKIyBjYWxjdWxhdGUgbG9nMkZDLCBhbmQgLWxvZzEwcApyZWRfdl95ZWxfdm9sY2Fub19kYXRhX25vT3V0bGllciA8LSAKICBiaW5kX2NvbHMocmVkX3ZfeWVsX3ZvbGNhbm9fZGF0YV9ub091dGxpZXIsIHJlZF92X3llbF90b2JpbmRfbm9PdXRsaWVyKSAlPiUKICBtdXRhdGUobG9nMl9GQ19wb3N0UmVkX2Rpdl9wb3N0WWVsbG93ID0gaWZfZWxzZShGQ19wb3N0UmVkX2Rpdl9wb3N0WWVsbG93ID4gMCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsb2cyKEZDX3Bvc3RSZWRfZGl2X3Bvc3RZZWxsb3cpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC0obG9nMihhYnMoRkNfcG9zdFJlZF9kaXZfcG9zdFllbGxvdykpKSksIAogICAgICAgICBuZWdsb2cxMHAgPSAtbG9nMTAocCkpCgoKIyBjcmVhdGUgYSBkZiBvZiBmZWF0dXJlcyBwYXNzaW5nIEZDIGFuZCBwdmFsIGN1dG9mZnMgaGlnaGVyIGluIHBvc3QtUmVkCnBvc3RSZWRfc2lnX3JlZF92X3llbF92b2xjYW5vX25vT3V0bGllciA8LSByZWRfdl95ZWxfdm9sY2Fub19kYXRhX25vT3V0bGllciAlPiUKICBmaWx0ZXIocCA8PSAwLjA1ICYgbG9nMl9GQ19wb3N0UmVkX2Rpdl9wb3N0WWVsbG93ID49IDAuNikKCiMgY3JlYXRlIGEgZGYgb2YgZmVhdHVyZXMgcGFzc2luZyBGQyBhbmQgcHZhbCBjdXRvZmZzIGhpZ2hlciBpbiBwb3N0LWNvbnRyb2wKcG9zdFllbGxvd19zaWdfcmVkX3ZfeWVsX3ZvbGNhbm9fbm9PdXRsaWVyIDwtIHJlZF92X3llbF92b2xjYW5vX2RhdGFfbm9PdXRsaWVyICU+JQogIGZpbHRlcihwIDw9IDAuMDUgJiBsb2cyX0ZDX3Bvc3RSZWRfZGl2X3Bvc3RZZWxsb3cgPD0gLTAuNikgIApgYGAKCiMjIyMjIEV4cG9ydCBzaWcgZmVhdHVyZXMKCkNyZWF0ZSBmZWF0dXJlIGxpc3RzIHdpdGggc2lnbmlmaWNhbnQgZmVhdHVyZXMgYWxvbmcgd2l0aCB0aGVpciBjbHVzdGVycwpgYGB7cn0KI3Bvc3QtUmVkIGxpc3QKcG9zdFJlZF9zaWdfaW50cnZudG5fY29tcF9jbHVzdGVycyA8LSBsZWZ0X2pvaW4ocG9zdFJlZF9zaWdfcmVkX3ZfeWVsX3ZvbGNhbm9fbm9PdXRsaWVyLCBjbHVzdGVyX2ZlYXR1cmVzLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJ5ID0gIm16X3J0IikKCndyaXRlX2Nzdihwb3N0UmVkX3NpZ19pbnRydm50bl9jb21wX2NsdXN0ZXJzLAogICAgICAgICAgIkZlYXR1cmUgbGlzdHMvcG9zdFJlZC1zaWdmZWF0dXJlcy1pbnRlcnZudG4tY29tcC5jc3YiKQoKI3Bvc3QtWWVsbG93IGxpc3QKcG9zdFllbGxvd19zaWdfaW50cnZudG5fY29tcF9jbHVzdGVycyA8LSBsZWZ0X2pvaW4ocG9zdFllbGxvd19zaWdfcmVkX3ZfeWVsX3ZvbGNhbm9fbm9PdXRsaWVyLCBjbHVzdGVyX2ZlYXR1cmVzLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJ5ID0gIm16X3J0IikKCndyaXRlX2Nzdihwb3N0WWVsbG93X3NpZ19pbnRydm50bl9jb21wX2NsdXN0ZXJzLAogICAgICAgICAgIkZlYXR1cmUgbGlzdHMvcG9zdFllbGxvdy1zaWdmZWF0dXJlcy1pbnRlcnZudG4tY29tcC5jc3YiKQpgYGAKCgojIyMjIyBQbG90CmBgYHtyfQoocmVkX3ZfeWVsbG93X3ZvbGNhbm9fbm9PdXRsaWVyIDwtIHJlZF92X3llbF92b2xjYW5vX2RhdGFfbm9PdXRsaWVyICU+JQogIGdncGxvdChhZXMoeCA9IGxvZzJfRkNfcG9zdFJlZF9kaXZfcG9zdFllbGxvdywgeSA9IG5lZ2xvZzEwcCwgCiAgICAgICAgICAgICB0ZXh0ID0gZ2x1ZSgiTWFzc19yZXRlbnRpb24gdGltZToge216X3J0fQogICAgICAgICAgICAgICAgICAgICAgICAgUC12YWx1ZToge3B9CiAgICAgICAgICAgICAgICAgICAgICAgICBGb2xkIGNoYW5nZSB0b21hdG8vY29udHJvbDoge3JvdW5kKEZDX3Bvc3RSZWRfZGl2X3Bvc3RZZWxsb3csIDIpfSIpKSkgKwogIGdlb21fcG9pbnQoY29sb3IgPSAiZ3JleSIpICsKICBnZW9tX3BvaW50KGRhdGEgPSBwb3N0UmVkX3NpZ19pbnRydm50bl9jb21wX2NsdXN0ZXJzLCAKICAgICAgICAgICAgIGFlcyh4ID0gbG9nMl9GQ19wb3N0UmVkX2Rpdl9wb3N0WWVsbG93LCB5ID0gbmVnbG9nMTBwKSwKICAgICAgICAgICAgIGNvbG9yID0gInRvbWF0byIpICsKICBnZW9tX3BvaW50KGRhdGEgPSBwb3N0WWVsbG93X3NpZ19pbnRydm50bl9jb21wX2NsdXN0ZXJzLCAKICAgICAgICAgICAgIGFlcyh4ID0gbG9nMl9GQ19wb3N0UmVkX2Rpdl9wb3N0WWVsbG93LCB5ID0gbmVnbG9nMTBwKSwKICAgICAgICAgICAgIGNvbG9yID0gInllbGxvdzIiKSArCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gMC42LCBsaW5ldHlwZSA9ICJkYXNoZWQiLCBjb2xvciA9ICJncmV5IikgKwogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IC0wLjYsIGxpbmV0eXBlID0gImRhc2hlZCIsIGNvbG9yID0gImdyZXkiKSArCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMS4zLCBsaW5ldHlwZSA9ICJkYXNoZWQiLCBjb2xvciA9ICJncmV5IikgKwogIGNvb3JkX2NhcnRlc2lhbih4bGltID0gYygtNSwgOCkpICsKICBsYWJzKHRpdGxlID0gIlZvbGNhbm8gUGxvdCBvZiBGZWF0dXJlcyBEaWZmZXJlbnQgaW4gUGVvcGxlIEFmdGVyIFRvbWF0by1Tb3kgYW5kIENvbnRyb2wgSnVpY2UgQ29uc3VtcHRpb24iLAogICAgICAgc3VidGl0bGUgPSAiUmVkIHBvaW50cyBhcmUgaGlnaGVyIGFmdGVyIHRvbWF0by1zb3kganVpY2UgY29uc3VtcHRpb24gd2hpbGUgeWVsbG93IHBvaW50cyBhcmUgaGlnaGVyIFxuYWZ0ZXIgY29udHJvbCB0b21hdG8ganVpY2UgY29uc3VtcHRpb24uIFN1YmplY3QgNjEwNiByZW1vdmVkIiwKICAgICAgIGNhcHRpb24gPSAiVmVydGljYWwgZGFzaGVkIGxpbmVzIHJlcHJlc2VudCBhIGxvZzIgZm9sZCBjaGFuZ2UgPiAwLjYgb3IgPCAtMC42LCBhbmQgaG9yaXpvbnRhbCBkYXNoZWQgbGluZSByZXByZXNlbnRzIGFuIEZEUiBjb3JyZWN0ZWQgXG5wLXZhbHVlIG9mIDAuMDUuIiwKICAgICAgIHggPSAiTG9nMiBGb2xkIENoYW5nZSAoVG9tYXRvU295L0NvbnRyb2wpIiwKICAgICAgIHkgPSAiLUxvZzEwKFAtdmFsdWUpIikgKwogIHRoZW1lX2J3KCkgKwogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyLCBoanVzdCA9IDApLAogICAgICAgIHBsb3QuY2FwdGlvbiA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSkpKQoKKHJlZF92X3llbGxvd192b2xjYW5vX2dncGxvdGx5X25vT3V0bGllciA8LSBnZ3Bsb3RseShyZWRfdl95ZWxsb3dfdm9sY2Fub19ub091dGxpZXIsIHRvb2x0aXAgPSAidGV4dCIpKQpgYGAKClNhdmUgcGxvdHMKYGBge3IsIGV2YWw9RkFMU0V9CiMgc2F2ZSB2b2xjYW5vIHBsb3QKZ2dzYXZlKHBsb3QgPSByZWRfdl95ZWxsb3dfdm9sY2Fub19ub091dGxpZXIsCiAgICAgICBmaWxlbmFtZSA9ICJwbG90cyBhbmQgZmlndXJlcy92b2xjYW5vIHBsb3RzL3JlZF92X3llbGxvd192b2xjYW5vX25vT3V0bGllci5zdmciKQoKIyBzYXZlIGludGVyYWN0aXZlIHZvbGNhbm8gcGxvdApzYXZlV2lkZ2V0KHdpZGdldCA9IHJlZF92X3llbGxvd192b2xjYW5vX2dncGxvdGx5X25vT3V0bGllciwKICAgICAgICAgICBmaWxlID0gInBsb3RzIGFuZCBmaWd1cmVzL3ZvbGNhbm8gcGxvdHMvaW50ZXJhY3RpdmVfcmVkdnllbGxvd192b2xjYW5vX3Bsb3Rfbm9PdXRsaWVyLmh0bWwiKQpgYGAKCgojIyMjIFJlZAoKIyMjIyMgV3JhbmdsZSAobm8gb3V0bGllcikKYGBge3J9CiMgY2FsY3VsYXRlIG1lYW4gcmVsIGFidW5kIChub3QgbG9nKSBieSBzYW1wbGUsIGFuZCBhdmcgZm9sZCBjaGFuZ2UgKEZDKSBkaWZmIGJ5IGZlYXR1cmUKcmVkX3ZvbGNhbm9fZGF0YV9ub091dGxpZXIgPC0gZGZfZm9yX3N0YXRzICU+JQogIGZpbHRlcihJbnRlcnZlbnRpb24gPT0gIlJlZCIsCiAgICAgICAgIFN1YmplY3QgIT0gNjEwNiwKICAgICAgICAgU3ViamVjdCAhPSA2MTEyKSAlPiUKICBncm91cF9ieShwcmVfcG9zdCwgbXpfcnQpICU+JQogIHN1bW1hcml6ZShtZWFuX3JlbF9hYnVuZCA9IG1lYW4oMl5yZWxfYWJ1bmRfbG9nMikpICU+JQogIHBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSBwcmVfcG9zdCwgdmFsdWVzX2Zyb20gPSBtZWFuX3JlbF9hYnVuZCkgJT4lCiAgbXV0YXRlKEZDX3Bvc3RfZGl2X3ByZSA9IHBvc3QvcHJlKSAKCiMgYmluZCBiYWNrIHB2YWwKcmVkX3RvYmluZF9ub091dGxpZXIgPC0gcmVkX25vT3V0bGllcl90LnRlc3RfcGFpcmVkICU+JQogIGRwbHlyOjpzZWxlY3QocCkKCiMgY2FsY3VsYXRlIGxvZzJGQywgYW5kIC1sb2cxMHAKcmVkX3ZvbGNhbm9fZGF0YV9ub091dGxpZXIgPC0gCiAgYmluZF9jb2xzKHJlZF92b2xjYW5vX2RhdGFfbm9PdXRsaWVyLCByZWRfdG9iaW5kX25vT3V0bGllcikgJT4lCiAgbXV0YXRlKGxvZzJfRkNfcG9zdF9kaXZfcHJlID0gbG9nMihGQ19wb3N0X2Rpdl9wcmUpLAogICAgICAgICBuZWdsb2cxMHAgPSAtbG9nMTAocCkpCgoKIyBjcmVhdGUgYSBkZiBvZiBmZWF0dXJlcyBwYXNzaW5nIEZDIGFuZCBwdmFsIGN1dG9mZnMgaGlnaGVyIGluIHBvc3QtaW50ZXJ2ZW50aW9uIGNvbXBhcmVkIHRvIHByZQpyZWRfcHJlX3ZfcG9zdF92b2xjYW5vX25vT3V0bGllciA8LSByZWRfdm9sY2Fub19kYXRhX25vT3V0bGllciAlPiUKICBmaWx0ZXIocCA8PSAwLjA1ICYgYWJzKGxvZzJfRkNfcG9zdF9kaXZfcHJlKSA+PSAwLjYpCgpgYGAKCiMjIyMjIEV4cG9ydCBzaWcgZmVhdHVyZXMKCkNyZWF0ZSBmZWF0dXJlIGxpc3RzIHdpdGggc2lnbmlmaWNhbnQgZmVhdHVyZXMgYWxvbmcgd2l0aCB0aGVpciBjbHVzdGVycwpgYGB7cn0KcmVkX3NpZ19wcmVwb3N0X2NvbXBfY2x1c3RlcnMgPC0gbGVmdF9qb2luKHJlZF9wcmVfdl9wb3N0X3ZvbGNhbm9fbm9PdXRsaWVyLCBjbHVzdGVyX2ZlYXR1cmVzLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJ5ID0gIm16X3J0IikKCndyaXRlX2NzdihyZWRfc2lnX3ByZXBvc3RfY29tcF9jbHVzdGVycywKICAgICAgICAgICJGZWF0dXJlIGxpc3RzL1JlZC1zaWdmZWF0dXJlcy1QcmV2c1Bvc3Qtbm9PdXRsaWVycy5jc3YiKQoKYGBgCgoKIyMjIyMgUGxvdApgYGB7cn0KKHJlZF92b2xjYW5vX25vT3V0bGllciA8LSByZWRfdm9sY2Fub19kYXRhX25vT3V0bGllciAlPiUKICBnZ3Bsb3QoYWVzKHggPSBsb2cyX0ZDX3Bvc3RfZGl2X3ByZSwgeSA9IG5lZ2xvZzEwcCwgCiAgICAgICAgICAgICB0ZXh0ID0gZ2x1ZSgiTWFzc19yZXRlbnRpb24gdGltZToge216X3J0fQogICAgICAgICAgICAgICAgICAgICAgICAgUC12YWx1ZToge3B9CiAgICAgICAgICAgICAgICAgICAgICAgICBGb2xkIGNoYW5nZSBwb3N0L3ByZToge3JvdW5kKEZDX3Bvc3RfZGl2X3ByZSwgMil9IikpKSArCiAgZ2VvbV9wb2ludChjb2xvciA9ICJncmV5IikgKwogIGdlb21fcG9pbnQoZGF0YSA9IHJlZF9zaWdfcHJlcG9zdF9jb21wX2NsdXN0ZXJzLCAKICAgICAgICAgICAgIGFlcyh4ID0gbG9nMl9GQ19wb3N0X2Rpdl9wcmUsIHkgPSBuZWdsb2cxMHApLAogICAgICAgICAgICAgY29sb3IgPSAidG9tYXRvIikgKwogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IDAuNiwgbGluZXR5cGUgPSAiZGFzaGVkIiwgY29sb3IgPSAiZ3JleSIpICsKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAtMC42LCBsaW5ldHlwZSA9ICJkYXNoZWQiLCBjb2xvciA9ICJncmV5IikgKyAKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAxLjMsIGxpbmV0eXBlID0gImRhc2hlZCIsIGNvbG9yID0gImdyZXkiKSArCiAgY29vcmRfY2FydGVzaWFuKHhsaW0gPSBjKC01LCA2KSkgKwogIGxhYnModGl0bGUgPSAiVm9sY2FubyBQbG90IG9mIEZlYXR1cmVzIERpZmZlcmVudCBpbiBQZW9wbGUgQWZ0ZXIgVG9tYXRvLVNveSBKdWljZSBDb25zdW1wdGlvbiIsCiAgICAgICBzdWJ0aXRsZSA9ICJSZWQgcG9pbnRzIGFyZSBoaWdoZXIgYWZ0ZXIgdG9tYXRvLXNveSBqdWljZSBjb25zdW1wdGlvbiB3aGVuIGNvbXBhcmVkIHRvIHByaW9yIHRvIGNvbnN1bXB0aW9uIiwKICAgICAgIGNhcHRpb24gPSAiVmVydGljYWwgZGFzaGVkIGxpbmVzIHJlcHJlc2VudCBhbiBhYnMobG9nIGZvbGQgY2hhbmdlKSA+IDAuNiwgYW5kIGhvcml6b250YWwgZGFzaGVkIGxpbmUgcmVwcmVzZW50cyBhbiBGRFIgY29ycmVjdGVkIFxucC12YWx1ZSBvZiAwLjA1LiIsCiAgICAgICB4ID0gIkxvZzIgRm9sZCBDaGFuZ2UgKFBvc3QvUHJlKSIsCiAgICAgICB5ID0gIi1Mb2cxMChQLXZhbHVlKSIpICsKICB0aGVtZV9idygpICsKICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiwgaGp1c3QgPSAwKSwKICAgICAgICBwbG90LmNhcHRpb24gPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpKSkKCihyZWRfdm9sY2Fub19nZ3Bsb3RseV9ub091dGxpZXIgPC0gZ2dwbG90bHkocmVkX3ZvbGNhbm9fbm9PdXRsaWVyLCB0b29sdGlwID0gInRleHQiKSkKYGBgCgpTYXZlIHBsb3RzCmBgYHtyLCBldmFsPUZBTFNFfQojIHNhdmUgdm9sY2FubyBwbG90Cmdnc2F2ZShwbG90ID0gcmVkX3ZvbGNhbm9fbm9PdXRsaWVyLAogICAgICAgZmlsZW5hbWUgPSAicGxvdHMgYW5kIGZpZ3VyZXMvdm9sY2FubyBwbG90cy9yZWRfdm9sY2Fub19ub091dGxpZXIuc3ZnIikKCiMgc2F2ZSBpbnRlcmFjdGl2ZSB2b2xjYW5vIHBsb3QKc2F2ZVdpZGdldCh3aWRnZXQgPSByZWRfdm9sY2Fub19nZ3Bsb3RseV9ub091dGxpZXIsCiAgICAgICAgICAgZmlsZSA9ICJwbG90cyBhbmQgZmlndXJlcy92b2xjYW5vIHBsb3RzL2ludGVyYWN0aXZlX3JlZF92b2xjYW5vX3Bsb3Rfbm9PdXRsaWVyLmh0bWwiKQpgYGAKCiMjIyMgWWVsbG93CgojIyMjIyBXcmFuZ2xlIChubyBvdXRsaWVyKQpgYGB7cn0KIyBjYWxjdWxhdGUgbWVhbiByZWwgYWJ1bmQgKG5vdCBsb2cpIGJ5IHNhbXBsZSwgYW5kIGF2ZyBmb2xkIGNoYW5nZSAoRkMpIGRpZmYgYnkgZmVhdHVyZQp5ZWxfdm9sY2Fub19kYXRhX25vT3V0bGllciA8LSBkZl9mb3Jfc3RhdHMgJT4lCiAgZmlsdGVyKEludGVydmVudGlvbiA9PSAiWWVsbG93IiwKICAgICAgICAgU3ViamVjdCAhPSA2MTA2LAogICAgICAgICBTdWJqZWN0ICE9IDYxMTIpICU+JQogIGdyb3VwX2J5KHByZV9wb3N0LCBtel9ydCkgJT4lCiAgc3VtbWFyaXplKG1lYW5fcmVsX2FidW5kID0gbWVhbigyXnJlbF9hYnVuZF9sb2cyKSkgJT4lCiAgcGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9IHByZV9wb3N0LCB2YWx1ZXNfZnJvbSA9IG1lYW5fcmVsX2FidW5kKSAlPiUKICBtdXRhdGUoRkNfcG9zdF9kaXZfcHJlID0gcG9zdC9wcmUpIAoKIyBiaW5kIGJhY2sgcHZhbAp5ZWxfdG9iaW5kX25vT3V0bGllciA8LSBjdHJsX25vT3V0bGllcl90LnRlc3RfcGFpcmVkICU+JQogIGRwbHlyOjpzZWxlY3QocCkKCiMgY2FsY3VsYXRlIGxvZzJGQywgYW5kIC1sb2cxMHAKeWVsX3ZvbGNhbm9fZGF0YV9ub091dGxpZXIgPC0gCiAgYmluZF9jb2xzKHllbF92b2xjYW5vX2RhdGFfbm9PdXRsaWVyLCB5ZWxfdG9iaW5kX25vT3V0bGllcikgJT4lCiAgbXV0YXRlKGxvZzJfRkNfcG9zdF9kaXZfcHJlID0gbG9nMihGQ19wb3N0X2Rpdl9wcmUpLAogICAgICAgICBuZWdsb2cxMHAgPSAtbG9nMTAocCkpCgoKIyBjcmVhdGUgYSBkZiBvZiBmZWF0dXJlcyBwYXNzaW5nIEZDIGFuZCBwdmFsIGN1dG9mZnMgaGlnaGVyIGluIHBvc3QtaW50ZXJ2ZW50aW9uIGNvbXBhcmVkIHRvIHByZQp5ZWxfcHJlX3ZfcG9zdF92b2xjYW5vX25vT3V0bGllciA8LSB5ZWxfdm9sY2Fub19kYXRhX25vT3V0bGllciAlPiUKICBmaWx0ZXIocCA8PSAwLjA1ICYgYWJzKGxvZzJfRkNfcG9zdF9kaXZfcHJlKSA+PSAwLjYpCgpgYGAKCiMjIyMjIEV4cG9ydCBzaWcgZmVhdHVyZXMKCkNyZWF0ZSBmZWF0dXJlIGxpc3RzIHdpdGggc2lnbmlmaWNhbnQgZmVhdHVyZXMgYWxvbmcgd2l0aCB0aGVpciBjbHVzdGVycwpgYGB7cn0KeWVsX3NpZ19wcmVwb3N0X2NvbXBfY2x1c3RlcnMgPC0gbGVmdF9qb2luKHllbF9wcmVfdl9wb3N0X3ZvbGNhbm9fbm9PdXRsaWVyLCBjbHVzdGVyX2ZlYXR1cmVzLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJ5ID0gIm16X3J0IikKCndyaXRlX2Nzdih5ZWxfc2lnX3ByZXBvc3RfY29tcF9jbHVzdGVycywKICAgICAgICAgICJGZWF0dXJlIGxpc3RzL1llbGxvdy1zaWdmZWF0dXJlcy1QcmV2c1Bvc3Qtbm9PdXRsaWVycy5jc3YiKQoKYGBgCgojIyMjIyBQbG90CmBgYHtyfQooeWVsX3ZvbGNhbm9fbm9PdXRsaWVyIDwtIHllbF92b2xjYW5vX2RhdGFfbm9PdXRsaWVyICU+JQogIGdncGxvdChhZXMoeCA9IGxvZzJfRkNfcG9zdF9kaXZfcHJlLCB5ID0gbmVnbG9nMTBwLCAKICAgICAgICAgICAgIHRleHQgPSBnbHVlKCJNYXNzX3JldGVudGlvbiB0aW1lOiB7bXpfcnR9CiAgICAgICAgICAgICAgICAgICAgICAgICBQLXZhbHVlOiB7cH0KICAgICAgICAgICAgICAgICAgICAgICAgIEZvbGQgY2hhbmdlIHBvc3QvcHJlOiB7cm91bmQoRkNfcG9zdF9kaXZfcHJlLCAyKX0iKSkpICsKICBnZW9tX3BvaW50KGNvbG9yID0gImdyZXkiKSArCiAgZ2VvbV9wb2ludChkYXRhID0geWVsX3NpZ19wcmVwb3N0X2NvbXBfY2x1c3RlcnMsIAogICAgICAgICAgICAgYWVzKHggPSBsb2cyX0ZDX3Bvc3RfZGl2X3ByZSwgeSA9IG5lZ2xvZzEwcCksCiAgICAgICAgICAgICBjb2xvciA9ICJ5ZWxsb3cyIikgKwogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IDAuNiwgbGluZXR5cGUgPSAiZGFzaGVkIiwgY29sb3IgPSAiZ3JleSIpICsKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAtMC42LCBsaW5ldHlwZSA9ICJkYXNoZWQiLCBjb2xvciA9ICJncmV5IikgKwogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDEuMywgbGluZXR5cGUgPSAiZGFzaGVkIiwgY29sb3IgPSAiZ3JleSIpICsKICBjb29yZF9jYXJ0ZXNpYW4oeGxpbSA9IGMoLTYsIDYpKSArCiAgbGFicyh0aXRsZSA9ICJWb2xjYW5vIFBsb3Qgb2YgRmVhdHVyZXMgRGlmZmVyZW50IGluIFBlb3BsZSBBZnRlciBDb250cm9sLCBZZWxsb3cgVG9tYXRvIEp1aWNlIENvbnN1bXB0aW9uIiwKICAgICAgIHN1YnRpdGxlID0gIlllbGxvdyBwb2ludHMgYXJlIGhpZ2hlciBhZnRlciBjb250cm9sIGp1aWNlIGNvbnN1bXB0aW9uIHdoZW4gY29tcGFyZWQgdG8gcHJpb3IgdG8gY29uc3VtcHRpb24uXG5TdWJqZWN0IDYxMDYgcmVtb3ZlZCIsCiAgICAgICBjYXB0aW9uID0gIlZlcnRpY2FsIGRhc2hlZCBsaW5lcyByZXByZXNlbnQgYWJzKGxvZzIgZm9sZCBjaGFuZ2UpID4gMC42LCBhbmQgaG9yaXpvbnRhbCBkYXNoZWQgbGluZSByZXByZXNlbnRzIGFuIEZEUiBjb3JyZWN0ZWQgXG5wLXZhbHVlIG9mIDAuMDUuIiwKICAgICAgIHggPSAiTG9nMiBGb2xkIENoYW5nZSAoUG9zdC9QcmUpIiwKICAgICAgIHkgPSAiLUxvZzEwKFAtdmFsdWUpIikgKwogIHRoZW1lX2J3KCkgKwogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyLCBoanVzdCA9IDApLAogICAgICAgIHBsb3QuY2FwdGlvbiA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSkpKQoKKHllbF92b2xjYW5vX2dncGxvdGx5X25vT3V0bGllciA8LSBnZ3Bsb3RseSh5ZWxfdm9sY2Fub19ub091dGxpZXIsIHRvb2x0aXAgPSAidGV4dCIpKQpgYGAKClNhdmUgcGxvdHMKYGBge3IsIGV2YWw9RkFMU0V9CiMgc2F2ZSB2b2xjYW5vIHBsb3QKZ2dzYXZlKHBsb3QgPSB5ZWxfdm9sY2Fub19ub091dGxpZXIsCiAgICAgICBmaWxlbmFtZSA9ICJwbG90cyBhbmQgZmlndXJlcy92b2xjYW5vIHBsb3RzL3llbF92b2xjYW5vX25vT3V0bGllci5zdmciKQoKIyBzYXZlIGludGVyYWN0aXZlIHZvbGNhbm8gcGxvdApzYXZlV2lkZ2V0KHdpZGdldCA9IHllbF92b2xjYW5vX2dncGxvdGx5X25vT3V0bGllciwKICAgICAgICAgICBmaWxlID0gInBsb3RzIGFuZCBmaWd1cmVzL3ZvbGNhbm8gcGxvdHMvaW50ZXJhY3RpdmVfeWVsX3ZvbGNhbm9fcGxvdF9ub091dGxpZXIuaHRtbCIpCmBgYAoKCiMjIEpvaW5lZCBsaXN0cwpIZXJlLCBJIHdhbnQgdG8gdmVubiBzaWduaWZpY2FudCBmZWF0dXJlcyBiZWZvcmUgSSBiZWdpbiB0byBsb29rIG1vcmUgaW50byB0aGVtLiBJIGFtIGludGVyZXN0ZWQgaW4gdGhlIGZvbGxvd2luZyBlZmZlY3RzOiB0b21hdG8gZWZmZWN0LCBseWNvcGVuZSBhbmQvb3Igc295IGlzb2ZsYXZvbmVzIGVmZmVjdC4KCiMjIyBUb21hdG8gZWZmZWN0CjEuIFRvbWF0byBlZmZlY3Q6IGpvaW4gYSBsaXN0IHRoYXQgb25seSBrZWVwcyBmZWF0dXJlcyB0aGF0IGFyZSBib3RoIHNpZ25pZmljYW50IGluIHByZSB2cy4gcG9zdC1yZWQgYW5kIHByZSB2cy4gcG9zdC15ZWxsb3cuCgpgYGB7cn0KIyBrZWVwIG9ubHkgZmVhdHVyZXMgcHJlc2VudCBpbiBib3RoIHByZSB2cyBwb3N0IHJlZCBhbmQgcHJlIHZzIHBvc3QgeWVsbG93CnRvbWF0b19lZmZlY3QgPC0gaW5uZXJfam9pbihyZWRfc2lnX3ByZXBvc3RfY29tcF9jbHVzdGVycywKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHllbF9zaWdfcHJlcG9zdF9jb21wX2NsdXN0ZXJzLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgYnkgPSAibXpfcnQiKQpkaW0odG9tYXRvX2VmZmVjdCkKYGBgCgpFeHBvcnQgdmVubmVkIGxpc3QKYGBge3J9CndyaXRlX2Nzdih0b21hdG9fZWZmZWN0LAogICAgICAgICAgIkZlYXR1cmUgbGlzdHMvc2lnLWZlYXR1cmVzLXRvbWF0by1lZmZlY3QuY3N2IikKYGBgCgoKCiMjIyMgQm94cGxvdHMKCgojIyMjIyBhbGwgc2lnIHRvbWF0byBmZWF0dXJlcwoKYGBge3J9CiMgYWRkIGluIEZlYXR1cmUgSUQgYW5ub3RhdGlvbnMKYW5ub190b21hdG9fZWZmZWN0IDwtIGxlZnRfam9pbih0b21hdG9fZWZmZWN0LCBkZl9mb3Jfc3RhdHNfbm9PdXRsaWVyLCBieSA9ICJtel9ydCIpCgojIG1ldGFicyB3aXRoIHB2YWwgPCAwLjA1IGFuZCBmYyA+PSAxLjUxCnNpZ21ldGFic190b21hdG9fZWZmZWN0IDwtIGFubm9fdG9tYXRvX2VmZmVjdCRGZWF0dXJlX0lECmBgYAoKYGBge3J9CnRvbWF0b19lZmZlY3RfZGZfZm9yX3N0YXRzX3dpZGUgPC0gZGZfZm9yX3N0YXRzX25vT3V0bGllcl93aWRlICU+JQogIGRwbHlyOjpzZWxlY3QoYygxOjExKSwKICAgICAgICAgICAgICAgIGFsbF9vZihzaWdtZXRhYnNfdG9tYXRvX2VmZmVjdCkpCgojIG1ha2UgdGlkeSBkZgp0b21hdG9fZWZmZWN0X2RmX2Zvcl9zdGF0c190aWR5IDwtIHRvbWF0b19lZmZlY3RfZGZfZm9yX3N0YXRzX3dpZGUgJT4lCiAgcGl2b3RfbG9uZ2VyKGNvbHMgPSAxMjpuY29sKC4pLAogICAgICAgICAgICAgICBuYW1lc190byA9ICJtel9ydCIsCiAgICAgICAgICAgICAgIHZhbHVlc190byA9ICJyZWxfYWJ1bmRfbG9nMiIpCmBgYAoKYGBge3J9CiMgY2hhbmdpbmcgZmFjdG9yIGxldmVscyBmb3IgcHJlX3Bvc3RfaW50ZXJ2ZW50aW9uCnRvbWF0b19lZmZlY3RfZGZfZm9yX3N0YXRzX3RpZHkkcHJlX3Bvc3RfaW50ZXJ2ZW50aW9uIDwtIGZhY3Rvcih0b21hdG9fZWZmZWN0X2RmX2Zvcl9zdGF0c190aWR5JHByZV9wb3N0X2ludGVydmVudGlvbiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGV2ZWxzID0gYygicHJlX1llbGxvdyIsICJwb3N0X1llbGxvdyIsICJwcmVfUmVkIiwgInBvc3RfUmVkIikpCgpsZXZlbHModG9tYXRvX2VmZmVjdF9kZl9mb3Jfc3RhdHNfdGlkeSRwcmVfcG9zdF9pbnRlcnZlbnRpb24pICAKYGBgCgpgYGB7ciwgZmlnLndpZHRoPTEwfQp0b21hdG9fZWZmZWN0X2RmX2Zvcl9zdGF0c190aWR5ICU+JSAKICBnZ3Bsb3QoYWVzKHggPSBwcmVfcG9zdF9pbnRlcnZlbnRpb24sIHkgPSByZWxfYWJ1bmRfbG9nMiwgZmlsbCA9IEludGVydmVudGlvbikpICsKICBnZW9tX2JveHBsb3Qob3V0bGllci5zaGFwZSA9IE5BKSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygiWWVsbG93IiA9ICJnb2xkIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJSZWQiID0gInRvbWF0bzEiKSkgKwogIGdlb21fbGluZShhZXMoZ3JvdXAgPSBTdWJqZWN0KSwgZmlsbCA9ICJicm93biIsIGxpbmV3aWR0aCA9IDAuMikgKwogIGZhY2V0X3dyYXAodmFycyhtel9ydCksIHNjYWxlcyA9ICJmcmVlX3kiKSArIAogIHRoZW1lX2NsZWFuKCkgCmBgYAoKTGV0J3MgbWFrZSB0aGVtIHByZXR0aWVyLgoKYGBge3J9Cm15X2NvbXBhcmlzb25zIDwtIGxpc3QoIGMoInByZV9ZZWxsb3ciLCAicG9zdF9ZZWxsb3ciKSwgYygicHJlX1JlZCIsICJwb3N0X1JlZCIpICkKCihicHNfdG9tYXRvZWZmZWN0X21ldGFicyA8LSB0b21hdG9fZWZmZWN0X2RmX2Zvcl9zdGF0c190aWR5ICU+JSAKICBnZ3BhaXJlZCh4ID0gInByZV9wb3N0X2ludGVydmVudGlvbiIsIHkgPSAicmVsX2FidW5kX2xvZzIiLCAKICAgICAgICAgICBmaWxsID0gIkludGVydmVudGlvbiIsIGxpbmUuY29sb3IgPSAiZ3JheSIsCiAgICAgICAgICAgaWQgPSAiU3ViamVjdCIsIGxpbmUuc2l6ZSA9IDAuMTUpICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCJSZWQiID0gInRvbWF0bzEiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlllbGxvdyIgPSAieWVsbG93MSIpLAogICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGMoIlRvbWF0by1Tb3kiLCAiQ29udHJvbCIpKSArCiAgZ2VvbV9wb2ludCgpICsKICBzY2FsZV94X2Rpc2NyZXRlKGxhYmVscyA9IGMoInByZSIsICJwb3N0IiwgInByZSIsICJwb3N0IikpICsKICBsYWJzKHggPSAiIiwKICAgICAgIHkgPSAiTG9nMiByZWxhdGl2ZSBhYnVuZGFuY2UiLAogICAgICAgdGl0bGUgPSAiIikgKwogIGZhY2V0X3dyYXAoIH4gbXpfcnQsIG5jb2wgPSAzLCBsYWJlbGxlciA9IGxhYmVsbGVyKG16X3J0ID0gbGFiZWxfd3JhcF9nZW4oMTMpKSkgKwogIHN0YXRfY29tcGFyZV9tZWFucyhjb21wYXJpc29ucyA9IG15X2NvbXBhcmlzb25zLCBtZXRob2QgPSAidC50ZXN0IiwgcGFpcmVkID0gVFJVRSwgcC5hZGp1c3QubWV0aG9kID0gIkJIIiwgbGFiZWwgPSAicC5zaWduaWYiKSArCiAgdGhlbWVfY2xhc3NpYyhiYXNlX3NpemUgPSAxNCwgYmFzZV9mYW1pbHkgPSAic2FucyIpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDApKSkKYGBgCgpgYGB7cn0KZ2dzYXZlKCJwbG90cyBhbmQgZmlndXJlcy9icHNfdG9tYXRvX2VmZmVjdC5zdmciKQpgYGAKCgojIyMgTHljL3NveSBlZmZlY3QKMi4gbHljb3BlbmUgYW5kL29yIHNveSBpc29mbGF2b25lcyBlZmZlY3Q6IGpvaW4gYSBsaXN0IHRoYXQgb25seSBrZWVwcyBmZWF0dXJlcyB0aGF0IGFyZToKLSBzaWduaWZpY2FudGx5IGRpZmZlcmVudCBiZXR3ZWVuIHBvc3QtUmVkIGFuZCBwb3N0LVllbGxvdwotIGFuZCBzaWduaWZpY2FudCBiZXR3ZWVuIHByZS0gYW5kIHBvc3QtUmVkLiAKCmBgYHtyfQojIGNvbWJpbmUgc2lnIGZlYXR1cmVzIGZyb20gcG9zdC1yZWQgdnMgcG9zdC15ZWxsb3cgY29tcGFyaXNvbgpzaWdfcG9zdGludGVydmVudGlvbl9ub091dGxpZXIgPC0gZnVsbF9qb2luKHBvc3RSZWRfc2lnX2ludHJ2bnRuX2NvbXBfY2x1c3RlcnMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcG9zdFllbGxvd19zaWdfaW50cnZudG5fY29tcF9jbHVzdGVycykKZGltKHNpZ19wb3N0aW50ZXJ2ZW50aW9uX25vT3V0bGllcikKCmBgYAoKYGBge3J9CiMgc2VsZWN0IG9ubHkgc2lnIGZlYXR1cmVzIHRoYXQgYXJlIHByZXNlbnQgd2hlbiBjb21wYXJpbmcgcHJlLVJlZCB0byBwb3N0LVJlZApseWNfc295X2VmZmVjdCA8LSBpbm5lcl9qb2luKHNpZ19wb3N0aW50ZXJ2ZW50aW9uX25vT3V0bGllciwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZWRfc2lnX3ByZXBvc3RfY29tcF9jbHVzdGVycywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBieSA9ICJtel9ydCIpIApkaW0obHljX3NveV9lZmZlY3QpCmBgYAoKCkV4cG9ydCB2ZW5uZWQgbGlzdApgYGB7cn0Kd3JpdGVfY3N2KGx5Y19zb3lfZWZmZWN0LAogICAgICAgICAgIkZlYXR1cmUgbGlzdHMvc2lnLWZlYXR1cmVzLWx5Yy1zb3ktZWZmZWN0LmNzdiIpCmBgYAoKCiMjIyMgQm94cGxvdHMKCgojIyMjIyBhbGwgc2lnIHRvbWF0byBmZWF0dXJlcwoKYGBge3J9CiMgYWRkIGluIEZlYXR1cmUgSUQgYW5ub3RhdGlvbnMKYW5ub19seWNzb3lfZWZmZWN0IDwtIGxlZnRfam9pbihseWNfc295X2VmZmVjdCwgZGZfZm9yX3N0YXRzX25vT3V0bGllciwgYnkgPSAibXpfcnQiKQoKIyBtZXRhYnMgd2l0aCBwdmFsIDwgMC4wNSBhbmQgZmMgPj0gMS41MQpzaWdtZXRhYnNfbHljc295X2VmZmVjdCA8LSBhbm5vX2x5Y3NveV9lZmZlY3QkRmVhdHVyZV9JRApgYGAKCmBgYHtyfQpseWNzb3lfZWZmZWN0X2RmX2Zvcl9zdGF0c193aWRlIDwtIGRmX2Zvcl9zdGF0c19ub091dGxpZXJfd2lkZSAlPiUKICBkcGx5cjo6c2VsZWN0KGMoMToxMSksCiAgICAgICAgICAgICAgICBhbGxfb2Yoc2lnbWV0YWJzX2x5Y3NveV9lZmZlY3QpKQoKIyBtYWtlIHRpZHkgZGYKbHljc295X2VmZmVjdF9kZl9mb3Jfc3RhdHNfdGlkeSA8LSBseWNzb3lfZWZmZWN0X2RmX2Zvcl9zdGF0c193aWRlICU+JQogIHBpdm90X2xvbmdlcihjb2xzID0gMTI6bmNvbCguKSwKICAgICAgICAgICAgICAgbmFtZXNfdG8gPSAibXpfcnQiLAogICAgICAgICAgICAgICB2YWx1ZXNfdG8gPSAicmVsX2FidW5kX2xvZzIiKQpgYGAKCmBgYHtyfQojIGNoYW5naW5nIGZhY3RvciBsZXZlbHMgZm9yIHByZV9wb3N0X2ludGVydmVudGlvbgpseWNzb3lfZWZmZWN0X2RmX2Zvcl9zdGF0c190aWR5JHByZV9wb3N0X2ludGVydmVudGlvbiA8LSBmYWN0b3IobHljc295X2VmZmVjdF9kZl9mb3Jfc3RhdHNfdGlkeSRwcmVfcG9zdF9pbnRlcnZlbnRpb24sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxldmVscyA9IGMoInByZV9ZZWxsb3ciLCAicG9zdF9ZZWxsb3ciLCAicHJlX1JlZCIsICJwb3N0X1JlZCIpKQoKbGV2ZWxzKGx5Y3NveV9lZmZlY3RfZGZfZm9yX3N0YXRzX3RpZHkkcHJlX3Bvc3RfaW50ZXJ2ZW50aW9uKSAgCmBgYAoKYGBge3IsIGZpZy5oZWlnaHQ9NDAsIGZpZy53aWR0aD0zMH0KbHljc295X2VmZmVjdF9kZl9mb3Jfc3RhdHNfdGlkeSAlPiUgCiAgZ2dwbG90KGFlcyh4ID0gcHJlX3Bvc3RfaW50ZXJ2ZW50aW9uLCB5ID0gcmVsX2FidW5kX2xvZzIsIGZpbGwgPSBJbnRlcnZlbnRpb24pKSArCiAgZ2VvbV9ib3hwbG90KG91dGxpZXIuc2hhcGUgPSBOQSkgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoIlllbGxvdyIgPSAiZ29sZCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiUmVkIiA9ICJ0b21hdG8xIikpICsKICBnZW9tX2xpbmUoYWVzKGdyb3VwID0gU3ViamVjdCksIGZpbGwgPSAiYnJvd24iLCBsaW5ld2lkdGggPSAwLjIpICsKICBmYWNldF93cmFwKHZhcnMobXpfcnQpLCBzY2FsZXMgPSAiZnJlZV95IikgKyAKICB0aGVtZV9jbGVhbigpIApgYGAKCgoKIyMjIExvdyBjYXJvdGVub2lkIHRvbWF0byBlZmZlY3QKMy4geWVsbG93IHRvbWF0byBlZmZlY3Q6IHVzZSBsaXN0IHRoYXQgb25seSBrZWVwcyBmZWF0dXJlcyB0aGF0IGFyZSBib3RoIHNpZ25pZmljYW50IGJldHdlZW4gcHJlIGFuZCBwb3N0LXllbGxvdywgYW5kIGFsc28gc2lnbmlmaWNhbnQgYmV0d2VlbiBwb3N0LVJlZCBhbmQgcG9zdC1ZZWxsb3cKYGBge3J9CiMgc2lnIGZlYXR1cmVzIGZyb20gcG9zdC1yZWQgdnMgcG9zdC15ZWxsb3cKZGltKHNpZ19wb3N0aW50ZXJ2ZW50aW9uX25vT3V0bGllcikKCiMgc2VsZWN0IG9ubHkgc2lnIGZlYXR1cmVzIHRoYXQgYXJlIHByZXNlbnQgd2hlbiBjb21wYXJpbmcgcHJlLVllbGxvdyB0byBwb3N0LVllbGxvdwpsb3dfY2Fyb3RfdG9tYXRvX2VmZmVjdCA8LSBpbm5lcl9qb2luKHNpZ19wb3N0aW50ZXJ2ZW50aW9uX25vT3V0bGllciwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5ZWxfc2lnX3ByZXBvc3RfY29tcF9jbHVzdGVycywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBieSA9ICJtel9ydCIpIApkaW0obG93X2Nhcm90X3RvbWF0b19lZmZlY3QpCmBgYAoKRXhwb3J0IHZlbm5lZCBsaXN0CmBgYHtyfQp3cml0ZV9jc3YobG93X2Nhcm90X3RvbWF0b19lZmZlY3QsCiAgICAgICAgICAiRmVhdHVyZSBsaXN0cy9zaWctZmVhdHVyZXMtbG93LWNhcm90LXRvbWF0by1lZmZlY3QuY3N2IikKYGBgCgoKCiMjIyMgQm94cGxvdHMKCgojIyMjIyBhbGwgc2lnIHllbGxvdyB0b20gZmVhdHVyZXMKCmBgYHtyfQojIGFkZCBpbiBGZWF0dXJlIElEIGFubm90YXRpb25zCmFubm9fbG93Y2Fyb3RfZWZmZWN0IDwtIGxlZnRfam9pbihsb3dfY2Fyb3RfdG9tYXRvX2VmZmVjdCwgZGZfZm9yX3N0YXRzX25vT3V0bGllciwgYnkgPSAibXpfcnQiKQoKIyBtZXRhYnMgd2l0aCBwdmFsIDwgMC4wNSBhbmQgZmMgPj0gMS41MQpzaWdtZXRhYnNfbG93Y2Fyb3RfZWZmZWN0IDwtIGFubm9fbG93Y2Fyb3RfZWZmZWN0JEZlYXR1cmVfSUQKYGBgCgpgYGB7cn0KeWVsbG93X2VmZmVjdF9kZl9mb3Jfc3RhdHNfd2lkZSA8LSBkZl9mb3Jfc3RhdHNfbm9PdXRsaWVyX3dpZGUgJT4lCiAgZHBseXI6OnNlbGVjdChjKDE6MTEpLAogICAgICAgICAgICAgICAgYWxsX29mKHNpZ21ldGFic19sb3djYXJvdF9lZmZlY3QpKQoKIyBtYWtlIHRpZHkgZGYKeWVsbG93X2VmZmVjdF9kZl9mb3Jfc3RhdHNfdGlkeSA8LSB5ZWxsb3dfZWZmZWN0X2RmX2Zvcl9zdGF0c193aWRlICU+JQogIHBpdm90X2xvbmdlcihjb2xzID0gMTI6bmNvbCguKSwKICAgICAgICAgICAgICAgbmFtZXNfdG8gPSAibXpfcnQiLAogICAgICAgICAgICAgICB2YWx1ZXNfdG8gPSAicmVsX2FidW5kX2xvZzIiKQpgYGAKCmBgYHtyfQojIGNoYW5naW5nIGZhY3RvciBsZXZlbHMgZm9yIHByZV9wb3N0X2ludGVydmVudGlvbgp5ZWxsb3dfZWZmZWN0X2RmX2Zvcl9zdGF0c190aWR5JHByZV9wb3N0X2ludGVydmVudGlvbiA8LSBmYWN0b3IoeWVsbG93X2VmZmVjdF9kZl9mb3Jfc3RhdHNfdGlkeSRwcmVfcG9zdF9pbnRlcnZlbnRpb24sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxldmVscyA9IGMoInByZV9ZZWxsb3ciLCAicG9zdF9ZZWxsb3ciLCAicHJlX1JlZCIsICJwb3N0X1JlZCIpKQoKbGV2ZWxzKHllbGxvd19lZmZlY3RfZGZfZm9yX3N0YXRzX3RpZHkkcHJlX3Bvc3RfaW50ZXJ2ZW50aW9uKSAgCmBgYAoKYGBge3IsIGZpZy53aWR0aD0xMn0KeWVsbG93X2VmZmVjdF9kZl9mb3Jfc3RhdHNfdGlkeSAlPiUgCiAgZ2dwbG90KGFlcyh4ID0gcHJlX3Bvc3RfaW50ZXJ2ZW50aW9uLCB5ID0gcmVsX2FidW5kX2xvZzIsIGZpbGwgPSBJbnRlcnZlbnRpb24pKSArCiAgZ2VvbV9ib3hwbG90KG91dGxpZXIuc2hhcGUgPSBOQSkgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoIlllbGxvdyIgPSAiZ29sZCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiUmVkIiA9ICJ0b21hdG8xIikpICsKICBnZW9tX2xpbmUoYWVzKGdyb3VwID0gU3ViamVjdCksIGZpbGwgPSAiYnJvd24iLCBsaW5ld2lkdGggPSAwLjIpICsKICBmYWNldF93cmFwKHZhcnMobXpfcnQpLCBzY2FsZXMgPSAiZnJlZV95IikgKyAKICB0aGVtZV9jbGVhbigpIApgYGAKCgo=